From 1be040382f1b1c9d745085ab75308cc7daa84993 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 17 May 2021 19:38:38 -0400 Subject: [PATCH 001/492] Use CRLF for line endings From dd7d36450b3b323eb6769b6a66517a000438d800 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 17 May 2021 19:51:05 -0400 Subject: [PATCH 002/492] v2-a134 Remove duplicate function and class --- ImagePut.ahk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index 7bb6ce15..aa86e686 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1779,8 +1779,8 @@ class ImagePut { } ; End of ImagePut class. -ImageEqual(images*) - => ImageEqual.call(images*) + + class ImageEqual extends ImagePut { From e6d0e5234691b26b55a25f9d8ead88f4f102cdba Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 17 May 2021 19:59:54 -0400 Subject: [PATCH 003/492] =?UTF-8?q?v2-a134=20BufferAlloc()=20=E2=86=92=20B?= =?UTF-8?q?uffer()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ImagePut.ahk | 80 ++++++++++++++++++++++++++-------------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index aa86e686..c98e2bdb 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -626,7 +626,7 @@ class ImagePut { ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") - bi := BufferAlloc(40, 0) ; sizeof(bi) = 40 + bi := Buffer(40, 0) ; sizeof(bi) = 40 , NumPut( "uint", 40, bi, 0) ; Size , NumPut( "int", image[3], bi, 4) ; Width , NumPut( "int", -image[4], bi, 8) ; Height - Negative so (0, 0) is top-left. @@ -668,14 +668,14 @@ class ImagePut { DllCall("ShowWindow", "ptr", image, "int", 4) ; Get the width and height of the client window. - Rect := BufferAlloc(16) ; sizeof(RECT) = 16 + Rect := Buffer(16) ; sizeof(RECT) = 16 DllCall("GetClientRect", "ptr", image, "ptr", Rect) , width := NumGet(Rect, 8, "int") , height := NumGet(Rect, 12, "int") ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") - bi := BufferAlloc(40, 0) ; sizeof(bi) = 40 + bi := Buffer(40, 0) ; sizeof(bi) = 40 , NumPut( "uint", 40, bi, 0) ; Size , NumPut( "int", width, bi, 4) ; Width , NumPut( "int", -height, bi, 8) ; Height - Negative so (0, 0) is top-left. @@ -714,7 +714,7 @@ class ImagePut { throw Error("Could not locate hidden window behind desktop.") ; Get the width and height of the client window. - Rect := BufferAlloc(16) ; sizeof(RECT) = 16 + Rect := Buffer(16) ; sizeof(RECT) = 16 DllCall("GetClientRect", "ptr", WorkerW, "ptr", Rect) , width := NumGet(Rect, 8, "int") , height := NumGet(Rect, 12, "int") @@ -724,7 +724,7 @@ class ImagePut { ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") - bi := BufferAlloc(40, 0) ; sizeof(bi) = 40 + bi := Buffer(40, 0) ; sizeof(bi) = 40 , NumPut( "uint", 40, bi, 0) ; Size , NumPut( "int", width, bi, 4) ; Width , NumPut( "int", -height, bi, 8) ; Height - Negative so (0, 0) is top-left. @@ -759,7 +759,7 @@ class ImagePut { ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") - bi := BufferAlloc(40, 0) ; sizeof(bi) = 40 + bi := Buffer(40, 0) ; sizeof(bi) = 40 , NumPut( "uint", 40, bi, 0) ; Size , NumPut( "int", width, bi, 4) ; Width , NumPut( "int", -height, bi, 8) ; Height - Negative so (0, 0) is top-left. @@ -786,10 +786,10 @@ class ImagePut { ; Thanks 23W - https://stackoverflow.com/a/13295280 ; struct CURSORINFO - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-cursorinfo - ci := BufferAlloc(16+A_PtrSize, 0) ; sizeof(CURSORINFO) = 20, 24 + ci := Buffer(16+A_PtrSize, 0) ; sizeof(CURSORINFO) = 20, 24 , NumPut("int", ci.size, ci) DllCall("GetCursorInfo", "ptr", ci) - ; cShow := NumGet(ci, 4, "int") ; 0x1 = CURSOR_SHOWING, 0x2 = CURSOR_SUPPRESSED + ; cShow := NumGet(ci, 4, "int") ; 0x1 = CURSOR_SHOWING, 0x2 = CURSOR_SUPPRESSED , hCursor := NumGet(ci, 8, "ptr") ; xCursor := NumGet(ci, 8+A_PtrSize, "int") ; yCursor := NumGet(ci, 12+A_PtrSize, "int") @@ -837,7 +837,7 @@ class ImagePut { static from_hBitmap(image) { ; struct DIBSECTION - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-dibsection ; struct BITMAP - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmap - dib := BufferAlloc(64+5*A_PtrSize) ; sizeof(DIBSECTION) = 84, 104 + dib := Buffer(64+5*A_PtrSize) ; sizeof(DIBSECTION) = 84, 104 DllCall("GetObject", "ptr", image, "int", dib.size, "ptr", dib) , width := NumGet(dib, 4, "uint") , height := NumGet(dib, 8, "uint") @@ -858,7 +858,7 @@ class ImagePut { ; pBits is the pointer to (top-down) pixel values. The Scan0 will point to the pBits. ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") - bi := BufferAlloc(40, 0) ; sizeof(bi) = 40 + bi := Buffer(40, 0) ; sizeof(bi) = 40 , NumPut( "uint", 40, bi, 0) ; Size , NumPut( "int", width, bi, 4) ; Width , NumPut( "int", -height, bi, 8) ; Height - Negative so (0, 0) is top-left. @@ -872,10 +872,10 @@ class ImagePut { , "int", width, "int", height, "int", 0, "int", 0x26200A, "ptr", 0, "ptr*", &pBitmap:=0) ; Create a Scan0 buffer pointing to pBits. The buffer has pixel format pARGB. - Rect := BufferAlloc(16, 0) ; sizeof(Rect) = 16 + Rect := Buffer(16, 0) ; sizeof(Rect) = 16 , NumPut( "uint", width, Rect, 8) ; Width , NumPut( "uint", height, Rect, 12) ; Height - BitmapData := BufferAlloc(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 , NumPut( "uint", width, BitmapData, 0) ; Width , NumPut( "uint", height, BitmapData, 4) ; Height , NumPut( "int", 4 * width, BitmapData, 8) ; Stride @@ -910,15 +910,15 @@ class ImagePut { static from_hIcon(image) { ; struct ICONINFO - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-iconinfo - ii := BufferAlloc(8+3*A_PtrSize, 0) ; sizeof(ICONINFO) = 20, 32 + ii := Buffer(8+3*A_PtrSize, 0) ; sizeof(ICONINFO) = 20, 32 DllCall("GetIconInfo", "ptr", image, "ptr", ii) ; xHotspot := NumGet(ii, 4, "uint") ; yHotspot := NumGet(ii, 8, "uint") - , hbmMask := NumGet(ii, 8+A_PtrSize, "ptr") ; x86:12, x64:16 - , hbmColor := NumGet(ii, 8+2*A_PtrSize, "ptr") ; x86:16, x64:24 + , hbmMask := NumGet(ii, 8+A_PtrSize, "ptr") ; 12, 16 + , hbmColor := NumGet(ii, 8+2*A_PtrSize, "ptr") ; 16, 24 ; struct BITMAP - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmap - bm := BufferAlloc(16+2*A_PtrSize) ; sizeof(BITMAP) = 24, 32 + bm := Buffer(16+2*A_PtrSize) ; sizeof(BITMAP) = 24, 32 DllCall("GetObject", "ptr", hbmMask, "int", bm.size, "ptr", bm) , width := NumGet(bm, 4, "uint") , height := NumGet(bm, 8, "uint") / (hbmColor ? 1 : 2) ; Black and White cursors have doubled height. @@ -929,7 +929,7 @@ class ImagePut { ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") - bi := BufferAlloc(40, 0) ; sizeof(bi) = 40 + bi := Buffer(40, 0) ; sizeof(bi) = 40 , NumPut( "uint", 40, bi, 0) ; Size , NumPut( "int", width, bi, 4) ; Width , NumPut( "int", -height, bi, 8) ; Height - Negative so (0, 0) is top-left. @@ -943,10 +943,10 @@ class ImagePut { , "int", width, "int", height, "int", 0, "int", 0x26200A, "ptr", 0, "ptr*", &pBitmap:=0) ; Create a Scan0 buffer pointing to pBits. The buffer has pixel format pARGB. - Rect := BufferAlloc(16, 0) ; sizeof(Rect) = 16 + Rect := Buffer(16, 0) ; sizeof(Rect) = 16 , NumPut( "uint", width, Rect, 8) ; Width , NumPut( "uint", height, Rect, 12) ; Height - BitmapData := BufferAlloc(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 , NumPut( "uint", width, BitmapData, 0) ; Width , NumPut( "uint", height, BitmapData, 4) ; Height , NumPut( "int", 4 * width, BitmapData, 8) ; Stride @@ -990,7 +990,7 @@ class ImagePut { static from_RandomAccessStream(image) { ; Get the Class ID from a GUID string. - CLSID := BufferAlloc(16, 0) + CLSID := Buffer(16, 0) if result := DllCall("ole32\CLSIDFromString", "wstr", "{0000000C-0000-0000-C000-000000000046}", "ptr", CLSID, "uint") throw Error("CLSIDFromString failed. Error: " . Format("{:#x}", result)) @@ -1014,7 +1014,7 @@ class ImagePut { ; Converts the image to binary data by first asking for the size. DllCall("crypt32\CryptStringToBinary" , "ptr", StrPtr(image), "uint", 0, "uint", 0x0000000C, "ptr", 0, "uint*", &size:=0, "ptr", 0, "ptr", 0) - bin := BufferAlloc(size, 0) + bin := Buffer(size, 0) DllCall("crypt32\CryptStringToBinary" , "ptr", StrPtr(image), "uint", 0, "uint", 0x0000000C, "ptr", bin, "uint*", size , "ptr", 0, "ptr", 0) @@ -1034,7 +1034,7 @@ class ImagePut { ; Converts the image to binary data by first asking for the size. DllCall("crypt32\CryptStringToBinary" , "ptr", StrPtr(image), "uint", 0, "uint", 0x00000001, "ptr", 0, "uint*", &size:=0, "ptr", 0, "ptr", 0) - bin := BufferAlloc(size, 0) + bin := Buffer(size, 0) DllCall("crypt32\CryptStringToBinary" , "ptr", StrPtr(image), "uint", 0, "uint", 0x00000001, "ptr", bin, "uint*", size , "ptr", 0, "ptr", 0) @@ -1142,10 +1142,10 @@ class ImagePut { , NumPut( "uint", 0x000000FF, pdib, 48) ; Blue ; Transfer data from source pBitmap to the global memory manually. - Rect := BufferAlloc(16, 0) ; sizeof(Rect) = 16 + Rect := Buffer(16, 0) ; sizeof(Rect) = 16 , NumPut( "uint", width, Rect, 8) ; Width , NumPut( "uint", height, Rect, 12) ; Height - BitmapData := BufferAlloc(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 , NumPut( "uint", width, BitmapData, 0) ; Width , NumPut( "uint", height, BitmapData, 4) ; Height , NumPut( "int", stride, BitmapData, 8) ; Stride @@ -1257,7 +1257,7 @@ class ImagePut { ; struct tagWNDCLASSEXA - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexa ; struct tagWNDCLASSEXW - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexw - WNDCLASSEX := BufferAlloc(A_PtrSize=8 ? 80:48, 0) ; sizeof(WNDCLASSEX) = 48, 80 + WNDCLASSEX := Buffer(A_PtrSize=8 ? 80:48, 0) ; sizeof(WNDCLASSEX) = 48, 80 , NumPut( "uint", WNDCLASSEX.size, WNDCLASSEX, 0) ; cbSize , NumPut( "uint", 0, WNDCLASSEX, 4) ; style , NumPut( "ptr", pWndProc, WNDCLASSEX, 8) ; lpfnWndProc @@ -1292,7 +1292,7 @@ class ImagePut { WS_EX_TRANSPARENT := 0x20 WS_EX_DLGMODALFRAME := 0x1 - rect := BufferAlloc(16, 0) + rect := Buffer(16, 0) , NumPut("int", Floor((A_ScreenWidth - width) / 2), rect, 0) , NumPut("int", Floor((A_ScreenHeight - height) / 2), rect, 4) , NumPut("int", Floor((A_ScreenWidth + width) / 2), rect, 8) @@ -1460,7 +1460,7 @@ class ImagePut { ; Sets the hotspot of the cursor by changing the icon into a cursor. if (xHotspot != "" || yHotspot != "") { ; struct ICONINFO - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-iconinfo - ii := BufferAlloc(8+3*A_PtrSize, 0) ; sizeof(ICONINFO) = 20, 32 + ii := Buffer(8+3*A_PtrSize, 0) ; sizeof(ICONINFO) = 20, 32 DllCall("GetIconInfo", "ptr", hIcon, "ptr", ii) ; Fill the ICONINFO structure. , NumPut("uint", false, ii, 0) ; true/false are icon/cursor respectively. , (xHotspot != "") ? NumPut("uint", xHotspot, ii, 4) : "" ; Set the xHotspot value. (Default: center point) @@ -1513,7 +1513,7 @@ class ImagePut { ; Fill a buffer with the available encoders. DllCall("gdiplus\GdipGetImageEncodersSize", "uint*", &count:=0, "uint*", &size:=0) - ci := BufferAlloc(size) + ci := Buffer(size) DllCall("gdiplus\GdipGetImageEncoders", "uint", count, "uint", size, "ptr", ci) if !(count && size) throw Error("Could not get a list of image codec encoders on this system.") @@ -1531,7 +1531,7 @@ class ImagePut { if (extension ~= "^(?i:jpg|jpeg|jpe|jfif)$" && IsInteger(quality) && 0 <= quality && quality <= 100 && quality != 75) { DllCall("gdiplus\GdipGetEncoderParameterListSize", "ptr", pBitmap, "ptr", pCodec, "uint*", &size:=0) - EncoderParameters := BufferAlloc(size, 0) + EncoderParameters := Buffer(size, 0) DllCall("gdiplus\GdipGetEncoderParameterList", "ptr", pBitmap, "ptr", pCodec, "uint", size, "ptr", EncoderParameters) ; Search for an encoder parameter with 1 value of type 6. @@ -1571,7 +1571,7 @@ class ImagePut { ; Convert the source pBitmap into a hBitmap manually. ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") - bi := BufferAlloc(40, 0) ; sizeof(bi) = 40 + bi := Buffer(40, 0) ; sizeof(bi) = 40 , NumPut( "uint", 40, bi, 0) ; Size , NumPut( "int", width, bi, 4) ; Width , NumPut( "int", -height, bi, 8) ; Height - Negative so (0, 0) is top-left. @@ -1581,10 +1581,10 @@ class ImagePut { obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") ; Transfer data from source pBitmap to an hBitmap manually. - Rect := BufferAlloc(16, 0) ; sizeof(Rect) = 16 + Rect := Buffer(16, 0) ; sizeof(Rect) = 16 , NumPut( "uint", width, Rect, 8) ; Width , NumPut( "uint", height, Rect, 12) ; Height - BitmapData := BufferAlloc(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 , NumPut( "uint", width, BitmapData, 0) ; Width , NumPut( "uint", height, BitmapData, 4) ; Height , NumPut( "int", 4 * width, BitmapData, 8) ; Stride @@ -1617,7 +1617,7 @@ class ImagePut { ; Fill a buffer with the available encoders. DllCall("gdiplus\GdipGetImageEncodersSize", "uint*", &count:=0, "uint*", &size:=0) - ci := BufferAlloc(size) + ci := Buffer(size) DllCall("gdiplus\GdipGetImageEncoders", "uint", count, "uint", size, "ptr", ci) if !(count && size) throw Error("Could not get a list of image codec encoders on this system.") @@ -1635,7 +1635,7 @@ class ImagePut { if (extension ~= "^(?i:jpg|jpeg|jpe|jfif)$" && IsInteger(quality) && 0 <= quality && quality <= 100 && quality != 75) { DllCall("gdiplus\GdipGetEncoderParameterListSize", "ptr", pBitmap, "ptr", pCodec, "uint*", &size:=0) - EncoderParameters := BufferAlloc(size, 0) + EncoderParameters := Buffer(size, 0) DllCall("gdiplus\GdipGetEncoderParameterList", "ptr", pBitmap, "ptr", pCodec, "uint", size, "ptr", EncoderParameters) ; Search for an encoder parameter with 1 value of type 6. @@ -1664,7 +1664,7 @@ class ImagePut { pStream := this.put_stream(pBitmap, extension, quality) ; Get the Class ID from a GUID string. - CLSID := BufferAlloc(16, 0) + CLSID := Buffer(16, 0) if result := DllCall("ole32\CLSIDFromString", "wstr", "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}", "ptr", CLSID, "uint") throw Error("CLSIDFromString failed. Error: " . Format("{:#x}", result)) @@ -1689,7 +1689,7 @@ class ImagePut { ; Using CryptBinaryToStringA saves about 2MB in memory. DllCall("Crypt32.dll\CryptBinaryToStringA", "ptr", pData, "uint", nSize, "uint", 0x4000000C, "ptr", 0, "uint*", &length:=0) - hex := BufferAlloc(length, 0) + hex := Buffer(length, 0) DllCall("Crypt32.dll\CryptBinaryToStringA", "ptr", pData, "uint", nSize, "uint", 0x4000000C, "ptr", hex, "uint*", length) DllCall("GlobalUnlock", "ptr", hData) @@ -1713,7 +1713,7 @@ class ImagePut { ; Using CryptBinaryToStringA saves about 2MB in memory. DllCall("Crypt32.dll\CryptBinaryToStringA", "ptr", pData, "uint", nSize, "uint", 0x40000001, "ptr", 0, "uint*", &length:=0) - base64 := BufferAlloc(length, 0) + base64 := Buffer(length, 0) DllCall("Crypt32.dll\CryptBinaryToStringA", "ptr", pData, "uint", nSize, "uint", 0x40000001, "ptr", base64, "uint*", length) DllCall("GlobalUnlock", "ptr", hData) @@ -1734,7 +1734,7 @@ class ImagePut { ; Startup gdiplus. DllCall("LoadLibrary", "str", "gdiplus") - si := BufferAlloc(A_PtrSize = 8 ? 24 : 16, 0) ; sizeof(GdiplusStartupInput) = 16, 24 + si := Buffer(A_PtrSize = 8 ? 24 : 16, 0) ; sizeof(GdiplusStartupInput) = 16, 24 , NumPut("uint", 0x1, si) DllCall("gdiplus\GdiplusStartup", "ptr*", &pToken:=0, "ptr", si, "ptr", 0) @@ -1846,7 +1846,7 @@ class ImageEqual extends ImagePut { return false ; struct RECT - https://docs.microsoft.com/en-us/windows/win32/api/windef/ns-windef-rect - Rect := BufferAlloc(16, 0) ; sizeof(Rect) = 16 + Rect := Buffer(16, 0) ; sizeof(Rect) = 16 , NumPut( "uint", Width1, Rect, 8) ; Width , NumPut( "uint", Height1, Rect, 12) ; Height @@ -1854,7 +1854,7 @@ class ImageEqual extends ImagePut { while ((i:=IsSet(i)?i:0)++ < 2) { ; for(int i = 0; i < 2; i++) ; Create a BitmapData structure. - BitmapData%i% := BufferAlloc(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + BitmapData%i% := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 ; Transfer the pixels to a read-only buffer. Avoid using a different PixelFormat. DllCall("gdiplus\GdipBitmapLockBits" From f30a6f46d6d6acd7f9d30a92953f36b22cb592ba Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 17 May 2021 20:52:42 -0400 Subject: [PATCH 004/492] Standardize file header --- ImagePut (for v1).ahk | 14 +++++--------- ImagePut.ahk | 14 +++++--------- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 1df090b0..a66948b5 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1,14 +1,10 @@ ; Script: ImagePut.ahk -; Author: iseahound ; License: MIT License -; Version: 2020-05-22 -; Release: 2020-10-14 - -; ImagePut - Windows Image Transformation Library -; Copy and paste functions from this reference libary as you wish. -; -> All put_XXX functions map from a pBitmap to XXX. -; -> All from_XXX functions map from XXX to a pBitmap. -; Or use ImagePut functions as part of your standard libary. +; Author: Edison Hua (iseahound) +; Date: 2021-05-17 +; Version: v1.00 + +#Requires AutoHotkey v1.1.33+ ; Puts the image into a file format and returns a base64 encoded string. diff --git a/ImagePut.ahk b/ImagePut.ahk index c98e2bdb..1dabf559 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1,14 +1,10 @@ ; Script: ImagePut.ahk -; Author: iseahound ; License: MIT License -; Version: 2020-05-22 -; Release: 2020-10-14 - -; ImagePut - Windows Image Transformation Library -; Copy and paste functions from this reference libary as you wish. -; -> All put_XXX functions map from a pBitmap to XXX. -; -> All from_XXX functions map from XXX to a pBitmap. -; Or use ImagePut functions as part of your standard libary. +; Author: Edison Hua (iseahound) +; Date: 2021-05-17 +; Version: v1.00 + +#Requires AutoHotkey v2-a134+ ; Puts the image into a file format and returns a base64 encoded string. From 3a105c9a2c0edcbaf429e6d6120ca074db596b76 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 17 May 2021 20:55:21 -0400 Subject: [PATCH 005/492] Remove commas before NumPut --- ImagePut (for v1).ahk | 200 +++++++++++++++++++++--------------------- ImagePut.ahk | 200 +++++++++++++++++++++--------------------- 2 files changed, 200 insertions(+), 200 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index a66948b5..79259351 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -623,11 +623,11 @@ class ImagePut { ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") VarSetCapacity(bi, 40, 0) ; sizeof(bi) = 40 - , NumPut( 40, bi, 0, "uint") ; Size - , NumPut( image[3], bi, 4, "uint") ; Width - , NumPut(-image[4], bi, 8, "int") ; Height - Negative so (0, 0) is top-left. - , NumPut( 1, bi, 12, "ushort") ; Planes - , NumPut( 32, bi, 14, "ushort") ; BitCount / BitsPerPixel + NumPut( 40, bi, 0, "uint") ; Size + NumPut( image[3], bi, 4, "uint") ; Width + NumPut(-image[4], bi, 8, "int") ; Height - Negative so (0, 0) is top-left. + NumPut( 1, bi, 12, "ushort") ; Planes + NumPut( 32, bi, 14, "ushort") ; BitCount / BitsPerPixel hbm := DllCall("CreateDIBSection", "ptr", hdc, "ptr", &bi, "uint", 0, "ptr*", pBits:=0, "ptr", 0, "uint", 0, "ptr") obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") @@ -672,11 +672,11 @@ class ImagePut { ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") VarSetCapacity(bi, 40, 0) ; sizeof(bi) = 40 - , NumPut( 40, bi, 0, "uint") ; Size - , NumPut( width, bi, 4, "uint") ; Width - , NumPut( -height, bi, 8, "int") ; Height - Negative so (0, 0) is top-left. - , NumPut( 1, bi, 12, "ushort") ; Planes - , NumPut( 32, bi, 14, "ushort") ; BitCount / BitsPerPixel + NumPut( 40, bi, 0, "uint") ; Size + NumPut( width, bi, 4, "uint") ; Width + NumPut( -height, bi, 8, "int") ; Height - Negative so (0, 0) is top-left. + NumPut( 1, bi, 12, "ushort") ; Planes + NumPut( 32, bi, 14, "ushort") ; BitCount / BitsPerPixel hbm := DllCall("CreateDIBSection", "ptr", hdc, "ptr", &bi, "uint", 0, "ptr*", pBits:=0, "ptr", 0, "uint", 0, "ptr") obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") @@ -721,11 +721,11 @@ class ImagePut { ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") VarSetCapacity(bi, 40, 0) ; sizeof(bi) = 40 - , NumPut( 40, bi, 0, "uint") ; Size - , NumPut( width, bi, 4, "uint") ; Width - , NumPut( -height, bi, 8, "int") ; Height - Negative so (0, 0) is top-left. - , NumPut( 1, bi, 12, "ushort") ; Planes - , NumPut( 32, bi, 14, "ushort") ; BitCount / BitsPerPixel + NumPut( 40, bi, 0, "uint") ; Size + NumPut( width, bi, 4, "uint") ; Width + NumPut( -height, bi, 8, "int") ; Height - Negative so (0, 0) is top-left. + NumPut( 1, bi, 12, "ushort") ; Planes + NumPut( 32, bi, 14, "ushort") ; BitCount / BitsPerPixel hbm := DllCall("CreateDIBSection", "ptr", hdc, "ptr", &bi, "uint", 0, "ptr*", pBits:=0, "ptr", 0, "uint", 0, "ptr") obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") @@ -756,11 +756,11 @@ class ImagePut { ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") VarSetCapacity(bi, 40, 0) ; sizeof(bi) = 40 - , NumPut( 40, bi, 0, "uint") ; Size - , NumPut( width, bi, 4, "uint") ; Width - , NumPut( -height, bi, 8, "int") ; Height - Negative so (0, 0) is top-left. - , NumPut( 1, bi, 12, "ushort") ; Planes - , NumPut( 32, bi, 14, "ushort") ; BitCount / BitsPerPixel + NumPut( 40, bi, 0, "uint") ; Size + NumPut( width, bi, 4, "uint") ; Width + NumPut( -height, bi, 8, "int") ; Height - Negative so (0, 0) is top-left. + NumPut( 1, bi, 12, "ushort") ; Planes + NumPut( 32, bi, 14, "ushort") ; BitCount / BitsPerPixel hbm := DllCall("CreateDIBSection", "ptr", hdc, "ptr", &bi, "uint", 0, "ptr*", pBits:=0, "ptr", 0, "uint", 0, "ptr") obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") @@ -783,7 +783,7 @@ class ImagePut { ; struct CURSORINFO - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-cursorinfo VarSetCapacity(ci, size := 16+A_PtrSize, 0) ; sizeof(CURSORINFO) = 20, 24 - , NumPut(size, ci, "int") + NumPut(size, ci, "int") DllCall("GetCursorInfo", "ptr", &ci) ; cShow := NumGet(ci, 4, "int") ; 0x1 = CURSOR_SHOWING, 0x2 = CURSOR_SUPPRESSED , hCursor := NumGet(ci, 8, "ptr") @@ -855,11 +855,11 @@ class ImagePut { ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") VarSetCapacity(bi, 40, 0) ; sizeof(bi) = 40 - , NumPut( 40, bi, 0, "uint") ; Size - , NumPut( width, bi, 4, "uint") ; Width - , NumPut( -height, bi, 8, "int") ; Height - Negative so (0, 0) is top-left. - , NumPut( 1, bi, 12, "ushort") ; Planes - , NumPut( 32, bi, 14, "ushort") ; BitCount / BitsPerPixel + NumPut( 40, bi, 0, "uint") ; Size + NumPut( width, bi, 4, "uint") ; Width + NumPut( -height, bi, 8, "int") ; Height - Negative so (0, 0) is top-left. + NumPut( 1, bi, 12, "ushort") ; Planes + NumPut( 32, bi, 14, "ushort") ; BitCount / BitsPerPixel hbm := DllCall("CreateDIBSection", "ptr", hdc, "ptr", &bi, "uint", 0, "ptr*", pBits:=0, "ptr", 0, "uint", 0, "ptr") obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") @@ -869,14 +869,14 @@ class ImagePut { ; Create a Scan0 buffer pointing to pBits. The buffer has pixel format pARGB. VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 - , NumPut( width, Rect, 8, "uint") ; Width - , NumPut( height, Rect, 12, "uint") ; Height + NumPut( width, Rect, 8, "uint") ; Width + NumPut( height, Rect, 12, "uint") ; Height VarSetCapacity(BitmapData, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 - , NumPut( width, BitmapData, 0, "uint") ; Width - , NumPut( height, BitmapData, 4, "uint") ; Height - , NumPut( 4 * width, BitmapData, 8, "int") ; Stride - , NumPut( 0xE200B, BitmapData, 12, "int") ; PixelFormat - , NumPut( pBits, BitmapData, 16, "ptr") ; Scan0 + NumPut( width, BitmapData, 0, "uint") ; Width + NumPut( height, BitmapData, 4, "uint") ; Height + NumPut( 4 * width, BitmapData, 8, "int") ; Stride + NumPut( 0xE200B, BitmapData, 12, "int") ; PixelFormat + NumPut( pBits, BitmapData, 16, "ptr") ; Scan0 ; Use LockBits to create a writable buffer that converts pARGB to ARGB. DllCall("gdiplus\GdipBitmapLockBits" @@ -926,11 +926,11 @@ class ImagePut { ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") VarSetCapacity(bi, 40, 0) ; sizeof(bi) = 40 - , NumPut( 40, bi, 0, "uint") ; Size - , NumPut( width, bi, 4, "uint") ; Width - , NumPut( -height, bi, 8, "int") ; Height - Negative so (0, 0) is top-left. - , NumPut( 1, bi, 12, "ushort") ; Planes - , NumPut( 32, bi, 14, "ushort") ; BitCount / BitsPerPixel + NumPut( 40, bi, 0, "uint") ; Size + NumPut( width, bi, 4, "uint") ; Width + NumPut( -height, bi, 8, "int") ; Height - Negative so (0, 0) is top-left. + NumPut( 1, bi, 12, "ushort") ; Planes + NumPut( 32, bi, 14, "ushort") ; BitCount / BitsPerPixel hbm := DllCall("CreateDIBSection", "ptr", hdc, "ptr", &bi, "uint", 0, "ptr*", pBits:=0, "ptr", 0, "uint", 0, "ptr") obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") @@ -940,14 +940,14 @@ class ImagePut { ; Create a Scan0 buffer pointing to pBits. The buffer has pixel format pARGB. VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 - , NumPut( width, Rect, 8, "uint") ; Width - , NumPut( height, Rect, 12, "uint") ; Height + NumPut( width, Rect, 8, "uint") ; Width + NumPut( height, Rect, 12, "uint") ; Height VarSetCapacity(BitmapData, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 - , NumPut( width, BitmapData, 0, "uint") ; Width - , NumPut( height, BitmapData, 4, "uint") ; Height - , NumPut( 4 * width, BitmapData, 8, "int") ; Stride - , NumPut( 0xE200B, BitmapData, 12, "int") ; PixelFormat - , NumPut( pBits, BitmapData, 16, "ptr") ; Scan0 + NumPut( width, BitmapData, 0, "uint") ; Width + NumPut( height, BitmapData, 4, "uint") ; Height + NumPut( 4 * width, BitmapData, 8, "int") ; Stride + NumPut( 0xE200B, BitmapData, 12, "int") ; PixelFormat + NumPut( pBits, BitmapData, 16, "ptr") ; Scan0 ; Use LockBits to create a writable buffer that converts pARGB to ARGB. DllCall("gdiplus\GdipBitmapLockBits" @@ -1125,28 +1125,28 @@ class ImagePut { ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdib := DllCall("GlobalAlloc", "uint", 0x42, "uptr", 40 + 12 + size, "ptr") pdib := DllCall("GlobalLock", "ptr", hdib, "ptr") - , NumPut( 40, pdib+0, 0, "uint") ; Size - , NumPut( width, pdib+0, 4, "int") ; Width - , NumPut( -height, pdib+0, 8, "int") ; Height - Negative so (0, 0) is top-left. - , NumPut( 1, pdib+0, 12, "ushort") ; Planes - , NumPut( bpp, pdib+0, 14, "ushort") ; BitCount / BitsPerPixel - , NumPut( 0x3, pdib+0, 16, "uint") ; Compression - , NumPut( size, pdib+0, 20, "uint") ; SizeImage (bytes) + NumPut( 40, pdib+0, 0, "uint") ; Size + NumPut( width, pdib+0, 4, "int") ; Width + NumPut( -height, pdib+0, 8, "int") ; Height - Negative so (0, 0) is top-left. + NumPut( 1, pdib+0, 12, "ushort") ; Planes + NumPut( bpp, pdib+0, 14, "ushort") ; BitCount / BitsPerPixel + NumPut( 0x3, pdib+0, 16, "uint") ; Compression + NumPut( size, pdib+0, 20, "uint") ; SizeImage (bytes) ; The following bitfields when masked extract the respective color channels. - , NumPut(0x00FF0000, pdib+0, 40, "uint") ; Red - , NumPut(0x0000FF00, pdib+0, 44, "uint") ; Green - , NumPut(0x000000FF, pdib+0, 48, "uint") ; Blue + NumPut(0x00FF0000, pdib+0, 40, "uint") ; Red + NumPut(0x0000FF00, pdib+0, 44, "uint") ; Green + NumPut(0x000000FF, pdib+0, 48, "uint") ; Blue ; Transfer data from source pBitmap to the global memory manually. VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 - , NumPut( width, Rect, 8, "uint") ; Width - , NumPut( height, Rect, 12, "uint") ; Height + NumPut( width, Rect, 8, "uint") ; Width + NumPut( height, Rect, 12, "uint") ; Height VarSetCapacity(BitmapData, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 - , NumPut( width, BitmapData, 0, "uint") ; Width - , NumPut( height, BitmapData, 4, "uint") ; Height - , NumPut( stride, BitmapData, 8, "int") ; Stride - , NumPut( format, BitmapData, 12, "int") ; PixelFormat - , NumPut( pdib + 52, BitmapData, 16, "ptr") ; Scan0 + NumPut( width, BitmapData, 0, "uint") ; Width + NumPut( height, BitmapData, 4, "uint") ; Height + NumPut( stride, BitmapData, 8, "int") ; Stride + NumPut( format, BitmapData, 12, "int") ; PixelFormat + NumPut( pdib + 52, BitmapData, 16, "ptr") ; Scan0 DllCall("gdiplus\GdipBitmapLockBits" , "ptr", pBitmap , "ptr", &Rect @@ -1254,18 +1254,18 @@ class ImagePut { ; struct tagWNDCLASSEXA - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexa ; struct tagWNDCLASSEXW - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexw VarSetCapacity(WNDCLASSEX, size := A_PtrSize=8 ? 80:48, 0) ; sizeof(WNDCLASSEX) = 48 or 80 - , NumPut( size, WNDCLASSEX, 0, "uint") ; cbSize - , NumPut( 0, WNDCLASSEX, 4, "uint") ; style - , NumPut( pWndProc, WNDCLASSEX, 8, "ptr") ; lpfnWndProc - , NumPut( 0, WNDCLASSEX, A_PtrSize=8 ? 16:12, "int") ; cbClsExtra - , NumPut( 0, WNDCLASSEX, A_PtrSize=8 ? 20:16, "int") ; cbWndExtra - , NumPut( 0, WNDCLASSEX, A_PtrSize=8 ? 24:20, "ptr") ; hInstance - , NumPut( 0, WNDCLASSEX, A_PtrSize=8 ? 32:24, "ptr") ; hIcon - , NumPut( hCursor, WNDCLASSEX, A_PtrSize=8 ? 40:28, "ptr") ; hCursor - , NumPut( hBrush, WNDCLASSEX, A_PtrSize=8 ? 48:32, "ptr") ; hbrBackground - , NumPut( 0, WNDCLASSEX, A_PtrSize=8 ? 56:36, "ptr") ; lpszMenuName - , NumPut( &class_name, WNDCLASSEX, A_PtrSize=8 ? 64:40, "ptr") ; lpszClassName - , NumPut( 0, WNDCLASSEX, A_PtrSize=8 ? 72:44, "ptr") ; hIconSm + NumPut( size, WNDCLASSEX, 0, "uint") ; cbSize + NumPut( 0, WNDCLASSEX, 4, "uint") ; style + NumPut( pWndProc, WNDCLASSEX, 8, "ptr") ; lpfnWndProc + NumPut( 0, WNDCLASSEX, A_PtrSize=8 ? 16:12, "int") ; cbClsExtra + NumPut( 0, WNDCLASSEX, A_PtrSize=8 ? 20:16, "int") ; cbWndExtra + NumPut( 0, WNDCLASSEX, A_PtrSize=8 ? 24:20, "ptr") ; hInstance + NumPut( 0, WNDCLASSEX, A_PtrSize=8 ? 32:24, "ptr") ; hIcon + NumPut( hCursor, WNDCLASSEX, A_PtrSize=8 ? 40:28, "ptr") ; hCursor + NumPut( hBrush, WNDCLASSEX, A_PtrSize=8 ? 48:32, "ptr") ; hbrBackground + NumPut( 0, WNDCLASSEX, A_PtrSize=8 ? 56:36, "ptr") ; lpszMenuName + NumPut( &class_name, WNDCLASSEX, A_PtrSize=8 ? 64:40, "ptr") ; lpszClassName + NumPut( 0, WNDCLASSEX, A_PtrSize=8 ? 72:44, "ptr") ; hIconSm ; Registers a window class for subsequent use in calls to the CreateWindow or CreateWindowEx function. DllCall("RegisterClassEx", "ptr", &WNDCLASSEX, "ushort") @@ -1289,10 +1289,10 @@ class ImagePut { WS_EX_DLGMODALFRAME := 0x1 VarSetCapacity(rect, 16, 0) - , NumPut(Floor((A_ScreenWidth - width) / 2), rect, 0, "int") - , NumPut(Floor((A_ScreenHeight - height) / 2), rect, 4, "int") - , NumPut(Floor((A_ScreenWidth + width) / 2), rect, 8, "int") - , NumPut(Floor((A_ScreenHeight + height) / 2), rect, 12, "int") + NumPut(Floor((A_ScreenWidth - width) / 2), rect, 0, "int") + NumPut(Floor((A_ScreenHeight - height) / 2), rect, 4, "int") + NumPut(Floor((A_ScreenWidth + width) / 2), rect, 8, "int") + NumPut(Floor((A_ScreenHeight + height) / 2), rect, 12, "int") style := WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_CLIPCHILDREN | WS_POPUP | WS_CLIPSIBLINGS ;| WS_SIZEBOX styleEx := WS_EX_TOPMOST | WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME ;| WS_EX_LAYERED ;| WS_EX_STATICEDGE @@ -1458,7 +1458,7 @@ class ImagePut { ; struct ICONINFO - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-iconinfo VarSetCapacity(ii, 8+3*A_PtrSize, 0) ; sizeof(ICONINFO) = 20, 32 DllCall("GetIconInfo", "ptr", hIcon, "ptr", &ii) ; Fill the ICONINFO structure. - , NumPut(false, ii, 0, "uint") ; true/false are icon/cursor respectively. + NumPut(false, ii, 0, "uint") ; true/false are icon/cursor respectively. , (xHotspot != "") ? NumPut(xHotspot, ii, 4, "uint") : "" ; Set the xHotspot value. (Default: center point) , (yHotspot != "") ? NumPut(yHotspot, ii, 8, "uint") : "" ; Set the yHotspot value. (Default: center point) DllCall("DestroyIcon", "ptr", hIcon) ; Destroy the icon after getting the ICONINFO structure. @@ -1537,9 +1537,9 @@ class ImagePut { ; struct EncoderParameter - http://www.jose.it-berater.org/gdiplus/reference/structures/encoderparameter.htm ep := &EncoderParameters + elem - A_PtrSize ; sizeof(EncoderParameter) = 28, 32 - , NumPut( 1, ep+0, 0, "uptr") ; Must be 1. - , NumPut( 4, ep+0, 20+A_PtrSize, "uint") ; Type - , NumPut(quality, NumGet(ep+24+A_PtrSize, "uptr"), "uint") ; Value (pointer) + NumPut( 1, ep+0, 0, "uptr") ; Must be 1. + NumPut( 4, ep+0, 20+A_PtrSize, "uint") ; Type + NumPut(quality, NumGet(ep+24+A_PtrSize, "uptr"), "uint") ; Value (pointer) } ; Write the file to disk using the specified encoder and encoding parameters. @@ -1568,24 +1568,24 @@ class ImagePut { ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") VarSetCapacity(bi, 40, 0) ; sizeof(bi) = 40 - , NumPut( 40, bi, 0, "uint") ; Size - , NumPut( width, bi, 4, "uint") ; Width - , NumPut( -height, bi, 8, "int") ; Height - Negative so (0, 0) is top-left. - , NumPut( 1, bi, 12, "ushort") ; Planes - , NumPut( 32, bi, 14, "ushort") ; BitCount / BitsPerPixel + NumPut( 40, bi, 0, "uint") ; Size + NumPut( width, bi, 4, "uint") ; Width + NumPut( -height, bi, 8, "int") ; Height - Negative so (0, 0) is top-left. + NumPut( 1, bi, 12, "ushort") ; Planes + NumPut( 32, bi, 14, "ushort") ; BitCount / BitsPerPixel hbm := DllCall("CreateDIBSection", "ptr", hdc, "ptr", &bi, "uint", 0, "ptr*", pBits:=0, "ptr", 0, "uint", 0, "ptr") obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") ; Transfer data from source pBitmap to an hBitmap manually. VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 - , NumPut( width, Rect, 8, "uint") ; Width - , NumPut( height, Rect, 12, "uint") ; Height + NumPut( width, Rect, 8, "uint") ; Width + NumPut( height, Rect, 12, "uint") ; Height VarSetCapacity(BitmapData, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 - , NumPut( width, BitmapData, 0, "uint") ; Width - , NumPut( height, BitmapData, 4, "uint") ; Height - , NumPut( 4 * width, BitmapData, 8, "int") ; Stride - , NumPut( 0xE200B, BitmapData, 12, "int") ; PixelFormat - , NumPut( pBits, BitmapData, 16, "ptr") ; Scan0 + NumPut( width, BitmapData, 0, "uint") ; Width + NumPut( height, BitmapData, 4, "uint") ; Height + NumPut( 4 * width, BitmapData, 8, "int") ; Stride + NumPut( 0xE200B, BitmapData, 12, "int") ; PixelFormat + NumPut( pBits, BitmapData, 16, "ptr") ; Scan0 DllCall("gdiplus\GdipBitmapLockBits" , "ptr", pBitmap , "ptr", &Rect @@ -1641,9 +1641,9 @@ class ImagePut { ; struct EncoderParameter - http://www.jose.it-berater.org/gdiplus/reference/structures/encoderparameter.htm ep := &EncoderParameters + elem - A_PtrSize ; sizeof(EncoderParameter) = 28, 32 - , NumPut( 1, ep+0, 0, "uptr") ; Must be 1. - , NumPut( 4, ep+0, 20+A_PtrSize, "uint") ; Type - , NumPut(quality, NumGet(ep+24+A_PtrSize, "uptr"), "uint") ; Value (pointer) + NumPut( 1, ep+0, 0, "uptr") ; Must be 1. + NumPut( 4, ep+0, 20+A_PtrSize, "uint") ; Type + NumPut(quality, NumGet(ep+24+A_PtrSize, "uptr"), "uint") ; Value (pointer) } ; Create a Stream. @@ -1731,7 +1731,7 @@ class ImagePut { ; Startup gdiplus. DllCall("LoadLibrary", "str", "gdiplus") VarSetCapacity(si, A_PtrSize = 8 ? 24 : 16, 0) ; sizeof(GdiplusStartupInput) = 16, 24 - , NumPut(0x1, si, "uint") + NumPut(0x1, si, "uint") DllCall("gdiplus\GdiplusStartup", "ptr*", pToken:=0, "ptr", &si, "ptr", 0) ImagePut.pToken := pToken @@ -1843,8 +1843,8 @@ class ImageEqual extends ImagePut { ; struct RECT - https://docs.microsoft.com/en-us/windows/win32/api/windef/ns-windef-rect VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 - , NumPut( Width1, Rect, 8, "uint") ; Width - , NumPut( Height1, Rect, 12, "uint") ; Height + NumPut( Width1, Rect, 8, "uint") ; Width + NumPut( Height1, Rect, 12, "uint") ; Height ; Do this twice. while ((i++:=i?i:0) < 2) { ; for(int i = 0; i < 2; i++) diff --git a/ImagePut.ahk b/ImagePut.ahk index 1dabf559..89e67313 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -623,11 +623,11 @@ class ImagePut { ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") bi := Buffer(40, 0) ; sizeof(bi) = 40 - , NumPut( "uint", 40, bi, 0) ; Size - , NumPut( "int", image[3], bi, 4) ; Width - , NumPut( "int", -image[4], bi, 8) ; Height - Negative so (0, 0) is top-left. - , NumPut("ushort", 1, bi, 12) ; Planes - , NumPut("ushort", 32, bi, 14) ; BitCount / BitsPerPixel + NumPut( "uint", 40, bi, 0) ; Size + NumPut( "int", image[3], bi, 4) ; Width + NumPut( "int", -image[4], bi, 8) ; Height - Negative so (0, 0) is top-left. + NumPut("ushort", 1, bi, 12) ; Planes + NumPut("ushort", 32, bi, 14) ; BitCount / BitsPerPixel hbm := DllCall("CreateDIBSection", "ptr", hdc, "ptr", bi, "uint", 0, "ptr*", &pBits:=0, "ptr", 0, "uint", 0, "ptr") obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") @@ -672,11 +672,11 @@ class ImagePut { ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") bi := Buffer(40, 0) ; sizeof(bi) = 40 - , NumPut( "uint", 40, bi, 0) ; Size - , NumPut( "int", width, bi, 4) ; Width - , NumPut( "int", -height, bi, 8) ; Height - Negative so (0, 0) is top-left. - , NumPut("ushort", 1, bi, 12) ; Planes - , NumPut("ushort", 32, bi, 14) ; BitCount / BitsPerPixel + NumPut( "uint", 40, bi, 0) ; Size + NumPut( "int", width, bi, 4) ; Width + NumPut( "int", -height, bi, 8) ; Height - Negative so (0, 0) is top-left. + NumPut("ushort", 1, bi, 12) ; Planes + NumPut("ushort", 32, bi, 14) ; BitCount / BitsPerPixel hbm := DllCall("CreateDIBSection", "ptr", hdc, "ptr", bi, "uint", 0, "ptr*", &pBits:=0, "ptr", 0, "uint", 0, "ptr") obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") @@ -721,11 +721,11 @@ class ImagePut { ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") bi := Buffer(40, 0) ; sizeof(bi) = 40 - , NumPut( "uint", 40, bi, 0) ; Size - , NumPut( "int", width, bi, 4) ; Width - , NumPut( "int", -height, bi, 8) ; Height - Negative so (0, 0) is top-left. - , NumPut("ushort", 1, bi, 12) ; Planes - , NumPut("ushort", 32, bi, 14) ; BitCount / BitsPerPixel + NumPut( "uint", 40, bi, 0) ; Size + NumPut( "int", width, bi, 4) ; Width + NumPut( "int", -height, bi, 8) ; Height - Negative so (0, 0) is top-left. + NumPut("ushort", 1, bi, 12) ; Planes + NumPut("ushort", 32, bi, 14) ; BitCount / BitsPerPixel hbm := DllCall("CreateDIBSection", "ptr", hdc, "ptr", bi, "uint", 0, "ptr*", &pBits:=0, "ptr", 0, "uint", 0, "ptr") obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") @@ -756,11 +756,11 @@ class ImagePut { ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") bi := Buffer(40, 0) ; sizeof(bi) = 40 - , NumPut( "uint", 40, bi, 0) ; Size - , NumPut( "int", width, bi, 4) ; Width - , NumPut( "int", -height, bi, 8) ; Height - Negative so (0, 0) is top-left. - , NumPut("ushort", 1, bi, 12) ; Planes - , NumPut("ushort", 32, bi, 14) ; BitCount / BitsPerPixel + NumPut( "uint", 40, bi, 0) ; Size + NumPut( "int", width, bi, 4) ; Width + NumPut( "int", -height, bi, 8) ; Height - Negative so (0, 0) is top-left. + NumPut("ushort", 1, bi, 12) ; Planes + NumPut("ushort", 32, bi, 14) ; BitCount / BitsPerPixel hbm := DllCall("CreateDIBSection", "ptr", hdc, "ptr", bi, "uint", 0, "ptr*", &pBits:=0, "ptr", 0, "uint", 0, "ptr") obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") @@ -783,7 +783,7 @@ class ImagePut { ; struct CURSORINFO - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-cursorinfo ci := Buffer(16+A_PtrSize, 0) ; sizeof(CURSORINFO) = 20, 24 - , NumPut("int", ci.size, ci) + NumPut("int", ci.size, ci) DllCall("GetCursorInfo", "ptr", ci) ; cShow := NumGet(ci, 4, "int") ; 0x1 = CURSOR_SHOWING, 0x2 = CURSOR_SUPPRESSED , hCursor := NumGet(ci, 8, "ptr") @@ -855,11 +855,11 @@ class ImagePut { ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") bi := Buffer(40, 0) ; sizeof(bi) = 40 - , NumPut( "uint", 40, bi, 0) ; Size - , NumPut( "int", width, bi, 4) ; Width - , NumPut( "int", -height, bi, 8) ; Height - Negative so (0, 0) is top-left. - , NumPut("ushort", 1, bi, 12) ; Planes - , NumPut("ushort", 32, bi, 14) ; BitCount / BitsPerPixel + NumPut( "uint", 40, bi, 0) ; Size + NumPut( "int", width, bi, 4) ; Width + NumPut( "int", -height, bi, 8) ; Height - Negative so (0, 0) is top-left. + NumPut("ushort", 1, bi, 12) ; Planes + NumPut("ushort", 32, bi, 14) ; BitCount / BitsPerPixel hbm := DllCall("CreateDIBSection", "ptr", hdc, "ptr", bi, "uint", 0, "ptr*", &pBits:=0, "ptr", 0, "uint", 0, "ptr") obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") @@ -869,14 +869,14 @@ class ImagePut { ; Create a Scan0 buffer pointing to pBits. The buffer has pixel format pARGB. Rect := Buffer(16, 0) ; sizeof(Rect) = 16 - , NumPut( "uint", width, Rect, 8) ; Width - , NumPut( "uint", height, Rect, 12) ; Height + NumPut( "uint", width, Rect, 8) ; Width + NumPut( "uint", height, Rect, 12) ; Height BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 - , NumPut( "uint", width, BitmapData, 0) ; Width - , NumPut( "uint", height, BitmapData, 4) ; Height - , NumPut( "int", 4 * width, BitmapData, 8) ; Stride - , NumPut( "int", 0xE200B, BitmapData, 12) ; PixelFormat - , NumPut( "ptr", pBits, BitmapData, 16) ; Scan0 + NumPut( "uint", width, BitmapData, 0) ; Width + NumPut( "uint", height, BitmapData, 4) ; Height + NumPut( "int", 4 * width, BitmapData, 8) ; Stride + NumPut( "int", 0xE200B, BitmapData, 12) ; PixelFormat + NumPut( "ptr", pBits, BitmapData, 16) ; Scan0 ; Use LockBits to create a writable buffer that converts pARGB to ARGB. DllCall("gdiplus\GdipBitmapLockBits" @@ -926,11 +926,11 @@ class ImagePut { ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") bi := Buffer(40, 0) ; sizeof(bi) = 40 - , NumPut( "uint", 40, bi, 0) ; Size - , NumPut( "int", width, bi, 4) ; Width - , NumPut( "int", -height, bi, 8) ; Height - Negative so (0, 0) is top-left. - , NumPut("ushort", 1, bi, 12) ; Planes - , NumPut("ushort", 32, bi, 14) ; BitCount / BitsPerPixel + NumPut( "uint", 40, bi, 0) ; Size + NumPut( "int", width, bi, 4) ; Width + NumPut( "int", -height, bi, 8) ; Height - Negative so (0, 0) is top-left. + NumPut("ushort", 1, bi, 12) ; Planes + NumPut("ushort", 32, bi, 14) ; BitCount / BitsPerPixel hbm := DllCall("CreateDIBSection", "ptr", hdc, "ptr", bi, "uint", 0, "ptr*", &pBits:=0, "ptr", 0, "uint", 0, "ptr") obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") @@ -940,14 +940,14 @@ class ImagePut { ; Create a Scan0 buffer pointing to pBits. The buffer has pixel format pARGB. Rect := Buffer(16, 0) ; sizeof(Rect) = 16 - , NumPut( "uint", width, Rect, 8) ; Width - , NumPut( "uint", height, Rect, 12) ; Height + NumPut( "uint", width, Rect, 8) ; Width + NumPut( "uint", height, Rect, 12) ; Height BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 - , NumPut( "uint", width, BitmapData, 0) ; Width - , NumPut( "uint", height, BitmapData, 4) ; Height - , NumPut( "int", 4 * width, BitmapData, 8) ; Stride - , NumPut( "int", 0xE200B, BitmapData, 12) ; PixelFormat - , NumPut( "ptr", pBits, BitmapData, 16) ; Scan0 + NumPut( "uint", width, BitmapData, 0) ; Width + NumPut( "uint", height, BitmapData, 4) ; Height + NumPut( "int", 4 * width, BitmapData, 8) ; Stride + NumPut( "int", 0xE200B, BitmapData, 12) ; PixelFormat + NumPut( "ptr", pBits, BitmapData, 16) ; Scan0 ; Use LockBits to create a writable buffer that converts pARGB to ARGB. DllCall("gdiplus\GdipBitmapLockBits" @@ -1125,28 +1125,28 @@ class ImagePut { ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdib := DllCall("GlobalAlloc", "uint", 0x42, "uptr", 40 + 12 + size, "ptr") pdib := DllCall("GlobalLock", "ptr", hdib, "ptr") - , NumPut( "uint", 40, pdib, 0) ; Size - , NumPut( "int", width, pdib, 4) ; Width - , NumPut( "int", -height, pdib, 8) ; Height - Negative so (0, 0) is top-left. - , NumPut("ushort", 1, pdib, 12) ; Planes - , NumPut("ushort", bpp, pdib, 14) ; BitCount / BitsPerPixel - , NumPut( "uint", 0x3, pdib, 16) ; Compression - , NumPut( "uint", size, pdib, 20) ; SizeImage (bytes) + NumPut( "uint", 40, pdib, 0) ; Size + NumPut( "int", width, pdib, 4) ; Width + NumPut( "int", -height, pdib, 8) ; Height - Negative so (0, 0) is top-left. + NumPut("ushort", 1, pdib, 12) ; Planes + NumPut("ushort", bpp, pdib, 14) ; BitCount / BitsPerPixel + NumPut( "uint", 0x3, pdib, 16) ; Compression + NumPut( "uint", size, pdib, 20) ; SizeImage (bytes) ; The following bitfields when masked extract the respective color channels. - , NumPut( "uint", 0x00FF0000, pdib, 40) ; Red - , NumPut( "uint", 0x0000FF00, pdib, 44) ; Green - , NumPut( "uint", 0x000000FF, pdib, 48) ; Blue + NumPut( "uint", 0x00FF0000, pdib, 40) ; Red + NumPut( "uint", 0x0000FF00, pdib, 44) ; Green + NumPut( "uint", 0x000000FF, pdib, 48) ; Blue ; Transfer data from source pBitmap to the global memory manually. Rect := Buffer(16, 0) ; sizeof(Rect) = 16 - , NumPut( "uint", width, Rect, 8) ; Width - , NumPut( "uint", height, Rect, 12) ; Height + NumPut( "uint", width, Rect, 8) ; Width + NumPut( "uint", height, Rect, 12) ; Height BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 - , NumPut( "uint", width, BitmapData, 0) ; Width - , NumPut( "uint", height, BitmapData, 4) ; Height - , NumPut( "int", stride, BitmapData, 8) ; Stride - , NumPut( "int", format, BitmapData, 12) ; PixelFormat - , NumPut( "ptr", pdib + 52, BitmapData, 16) ; Scan0 + NumPut( "uint", width, BitmapData, 0) ; Width + NumPut( "uint", height, BitmapData, 4) ; Height + NumPut( "int", stride, BitmapData, 8) ; Stride + NumPut( "int", format, BitmapData, 12) ; PixelFormat + NumPut( "ptr", pdib + 52, BitmapData, 16) ; Scan0 DllCall("gdiplus\GdipBitmapLockBits" , "ptr", pBitmap , "ptr", Rect @@ -1254,18 +1254,18 @@ class ImagePut { ; struct tagWNDCLASSEXA - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexa ; struct tagWNDCLASSEXW - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexw WNDCLASSEX := Buffer(A_PtrSize=8 ? 80:48, 0) ; sizeof(WNDCLASSEX) = 48, 80 - , NumPut( "uint", WNDCLASSEX.size, WNDCLASSEX, 0) ; cbSize - , NumPut( "uint", 0, WNDCLASSEX, 4) ; style - , NumPut( "ptr", pWndProc, WNDCLASSEX, 8) ; lpfnWndProc - , NumPut( "int", 0, WNDCLASSEX, A_PtrSize=8 ? 16:12) ; cbClsExtra - , NumPut( "int", 0, WNDCLASSEX, A_PtrSize=8 ? 20:16) ; cbWndExtra - , NumPut( "ptr", 0, WNDCLASSEX, A_PtrSize=8 ? 24:20) ; hInstance - , NumPut( "ptr", 0, WNDCLASSEX, A_PtrSize=8 ? 32:24) ; hIcon - , NumPut( "ptr", hCursor, WNDCLASSEX, A_PtrSize=8 ? 40:28) ; hCursor - , NumPut( "ptr", hBrush, WNDCLASSEX, A_PtrSize=8 ? 48:32) ; hbrBackground - , NumPut( "ptr", 0, WNDCLASSEX, A_PtrSize=8 ? 56:36) ; lpszMenuName - , NumPut( "ptr", StrPtr(class_name), WNDCLASSEX, A_PtrSize=8 ? 64:40) ; lpszClassName - , NumPut( "ptr", 0, WNDCLASSEX, A_PtrSize=8 ? 72:44) ; hIconSm + NumPut( "uint", WNDCLASSEX.size, WNDCLASSEX, 0) ; cbSize + NumPut( "uint", 0, WNDCLASSEX, 4) ; style + NumPut( "ptr", pWndProc, WNDCLASSEX, 8) ; lpfnWndProc + NumPut( "int", 0, WNDCLASSEX, A_PtrSize=8 ? 16:12) ; cbClsExtra + NumPut( "int", 0, WNDCLASSEX, A_PtrSize=8 ? 20:16) ; cbWndExtra + NumPut( "ptr", 0, WNDCLASSEX, A_PtrSize=8 ? 24:20) ; hInstance + NumPut( "ptr", 0, WNDCLASSEX, A_PtrSize=8 ? 32:24) ; hIcon + NumPut( "ptr", hCursor, WNDCLASSEX, A_PtrSize=8 ? 40:28) ; hCursor + NumPut( "ptr", hBrush, WNDCLASSEX, A_PtrSize=8 ? 48:32) ; hbrBackground + NumPut( "ptr", 0, WNDCLASSEX, A_PtrSize=8 ? 56:36) ; lpszMenuName + NumPut( "ptr", StrPtr(class_name), WNDCLASSEX, A_PtrSize=8 ? 64:40) ; lpszClassName + NumPut( "ptr", 0, WNDCLASSEX, A_PtrSize=8 ? 72:44) ; hIconSm ; Registers a window class for subsequent use in calls to the CreateWindow or CreateWindowEx function. DllCall("RegisterClassEx", "ptr", WNDCLASSEX, "ushort") @@ -1289,10 +1289,10 @@ class ImagePut { WS_EX_DLGMODALFRAME := 0x1 rect := Buffer(16, 0) - , NumPut("int", Floor((A_ScreenWidth - width) / 2), rect, 0) - , NumPut("int", Floor((A_ScreenHeight - height) / 2), rect, 4) - , NumPut("int", Floor((A_ScreenWidth + width) / 2), rect, 8) - , NumPut("int", Floor((A_ScreenHeight + height) / 2), rect, 12) + NumPut("int", Floor((A_ScreenWidth - width) / 2), rect, 0) + NumPut("int", Floor((A_ScreenHeight - height) / 2), rect, 4) + NumPut("int", Floor((A_ScreenWidth + width) / 2), rect, 8) + NumPut("int", Floor((A_ScreenHeight + height) / 2), rect, 12) style := WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_CLIPCHILDREN | WS_POPUP | WS_CLIPSIBLINGS ;| WS_SIZEBOX styleEx := WS_EX_TOPMOST | WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME ;| WS_EX_LAYERED ;| WS_EX_STATICEDGE @@ -1458,7 +1458,7 @@ class ImagePut { ; struct ICONINFO - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-iconinfo ii := Buffer(8+3*A_PtrSize, 0) ; sizeof(ICONINFO) = 20, 32 DllCall("GetIconInfo", "ptr", hIcon, "ptr", ii) ; Fill the ICONINFO structure. - , NumPut("uint", false, ii, 0) ; true/false are icon/cursor respectively. + NumPut("uint", false, ii, 0) ; true/false are icon/cursor respectively. , (xHotspot != "") ? NumPut("uint", xHotspot, ii, 4) : "" ; Set the xHotspot value. (Default: center point) , (yHotspot != "") ? NumPut("uint", yHotspot, ii, 8) : "" ; Set the yHotspot value. (Default: center point) DllCall("DestroyIcon", "ptr", hIcon) ; Destroy the icon after getting the ICONINFO structure. @@ -1537,9 +1537,9 @@ class ImagePut { ; struct EncoderParameter - http://www.jose.it-berater.org/gdiplus/reference/structures/encoderparameter.htm ep := EncoderParameters.ptr + elem - A_PtrSize ; sizeof(EncoderParameter) = 28, 32 - , NumPut( "uptr", 1, ep) ; Must be 1. - , NumPut( "uint", 4, ep, 20+A_PtrSize) ; Type - , NumPut( "uint", quality, NumGet(ep+24+A_PtrSize, "uptr")) ; Value (pointer) + NumPut( "uptr", 1, ep) ; Must be 1. + NumPut( "uint", 4, ep, 20+A_PtrSize) ; Type + NumPut( "uint", quality, NumGet(ep+24+A_PtrSize, "uptr")) ; Value (pointer) } ; Write the file to disk using the specified encoder and encoding parameters. @@ -1568,24 +1568,24 @@ class ImagePut { ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") bi := Buffer(40, 0) ; sizeof(bi) = 40 - , NumPut( "uint", 40, bi, 0) ; Size - , NumPut( "int", width, bi, 4) ; Width - , NumPut( "int", -height, bi, 8) ; Height - Negative so (0, 0) is top-left. - , NumPut("ushort", 1, bi, 12) ; Planes - , NumPut("ushort", 32, bi, 14) ; BitCount / BitsPerPixel + NumPut( "uint", 40, bi, 0) ; Size + NumPut( "int", width, bi, 4) ; Width + NumPut( "int", -height, bi, 8) ; Height - Negative so (0, 0) is top-left. + NumPut("ushort", 1, bi, 12) ; Planes + NumPut("ushort", 32, bi, 14) ; BitCount / BitsPerPixel hbm := DllCall("CreateDIBSection", "ptr", hdc, "ptr", bi, "uint", 0, "ptr*", &pBits:=0, "ptr", 0, "uint", 0, "ptr") obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") ; Transfer data from source pBitmap to an hBitmap manually. Rect := Buffer(16, 0) ; sizeof(Rect) = 16 - , NumPut( "uint", width, Rect, 8) ; Width - , NumPut( "uint", height, Rect, 12) ; Height + NumPut( "uint", width, Rect, 8) ; Width + NumPut( "uint", height, Rect, 12) ; Height BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 - , NumPut( "uint", width, BitmapData, 0) ; Width - , NumPut( "uint", height, BitmapData, 4) ; Height - , NumPut( "int", 4 * width, BitmapData, 8) ; Stride - , NumPut( "int", 0xE200B, BitmapData, 12) ; PixelFormat - , NumPut( "ptr", pBits, BitmapData, 16) ; Scan0 + NumPut( "uint", width, BitmapData, 0) ; Width + NumPut( "uint", height, BitmapData, 4) ; Height + NumPut( "int", 4 * width, BitmapData, 8) ; Stride + NumPut( "int", 0xE200B, BitmapData, 12) ; PixelFormat + NumPut( "ptr", pBits, BitmapData, 16) ; Scan0 DllCall("gdiplus\GdipBitmapLockBits" , "ptr", pBitmap , "ptr", Rect @@ -1641,9 +1641,9 @@ class ImagePut { ; struct EncoderParameter - http://www.jose.it-berater.org/gdiplus/reference/structures/encoderparameter.htm ep := EncoderParameters.ptr + elem - A_PtrSize ; sizeof(EncoderParameter) = 28, 32 - , NumPut( "uptr", 1, ep) ; Must be 1. - , NumPut( "uint", 4, ep, 20+A_PtrSize) ; Type - , NumPut( "uint", quality, NumGet(ep+24+A_PtrSize, "uptr")) ; Value (pointer) + NumPut( "uptr", 1, ep) ; Must be 1. + NumPut( "uint", 4, ep, 20+A_PtrSize) ; Type + NumPut( "uint", quality, NumGet(ep+24+A_PtrSize, "uptr")) ; Value (pointer) } ; Create a Stream. @@ -1731,7 +1731,7 @@ class ImagePut { ; Startup gdiplus. DllCall("LoadLibrary", "str", "gdiplus") si := Buffer(A_PtrSize = 8 ? 24 : 16, 0) ; sizeof(GdiplusStartupInput) = 16, 24 - , NumPut("uint", 0x1, si) + NumPut("uint", 0x1, si) DllCall("gdiplus\GdiplusStartup", "ptr*", &pToken:=0, "ptr", si, "ptr", 0) ImagePut.pToken := pToken @@ -1843,8 +1843,8 @@ class ImageEqual extends ImagePut { ; struct RECT - https://docs.microsoft.com/en-us/windows/win32/api/windef/ns-windef-rect Rect := Buffer(16, 0) ; sizeof(Rect) = 16 - , NumPut( "uint", Width1, Rect, 8) ; Width - , NumPut( "uint", Height1, Rect, 12) ; Height + NumPut( "uint", Width1, Rect, 8) ; Width + NumPut( "uint", Height1, Rect, 12) ; Height ; Do this twice. while ((i:=IsSet(i)?i:0)++ < 2) { ; for(int i = 0; i < 2; i++) From d32e3ac415b3175498479ac3ea449efaf1f05a15 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 17 May 2021 21:04:25 -0400 Subject: [PATCH 006/492] Adjust spacing of comments from NumPut changes --- ImagePut (for v1).ahk | 56 +++++++++++++++++++++---------------------- ImagePut.ahk | 52 ++++++++++++++++++++-------------------- 2 files changed, 54 insertions(+), 54 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 79259351..da890185 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -622,7 +622,7 @@ class ImagePut { ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") - VarSetCapacity(bi, 40, 0) ; sizeof(bi) = 40 + VarSetCapacity(bi, 40, 0) ; sizeof(bi) = 40 NumPut( 40, bi, 0, "uint") ; Size NumPut( image[3], bi, 4, "uint") ; Width NumPut(-image[4], bi, 8, "int") ; Height - Negative so (0, 0) is top-left. @@ -671,7 +671,7 @@ class ImagePut { ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") - VarSetCapacity(bi, 40, 0) ; sizeof(bi) = 40 + VarSetCapacity(bi, 40, 0) ; sizeof(bi) = 40 NumPut( 40, bi, 0, "uint") ; Size NumPut( width, bi, 4, "uint") ; Width NumPut( -height, bi, 8, "int") ; Height - Negative so (0, 0) is top-left. @@ -720,7 +720,7 @@ class ImagePut { ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") - VarSetCapacity(bi, 40, 0) ; sizeof(bi) = 40 + VarSetCapacity(bi, 40, 0) ; sizeof(bi) = 40 NumPut( 40, bi, 0, "uint") ; Size NumPut( width, bi, 4, "uint") ; Width NumPut( -height, bi, 8, "int") ; Height - Negative so (0, 0) is top-left. @@ -755,7 +755,7 @@ class ImagePut { ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") - VarSetCapacity(bi, 40, 0) ; sizeof(bi) = 40 + VarSetCapacity(bi, 40, 0) ; sizeof(bi) = 40 NumPut( 40, bi, 0, "uint") ; Size NumPut( width, bi, 4, "uint") ; Width NumPut( -height, bi, 8, "int") ; Height - Negative so (0, 0) is top-left. @@ -782,10 +782,10 @@ class ImagePut { ; Thanks 23W - https://stackoverflow.com/a/13295280 ; struct CURSORINFO - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-cursorinfo - VarSetCapacity(ci, size := 16+A_PtrSize, 0) ; sizeof(CURSORINFO) = 20, 24 + VarSetCapacity(ci, size := 16+A_PtrSize, 0) ; sizeof(CURSORINFO) = 20, 24 NumPut(size, ci, "int") DllCall("GetCursorInfo", "ptr", &ci) - ; cShow := NumGet(ci, 4, "int") ; 0x1 = CURSOR_SHOWING, 0x2 = CURSOR_SUPPRESSED + ; cShow := NumGet(ci, 4, "int") ; 0x1 = CURSOR_SHOWING, 0x2 = CURSOR_SUPPRESSED , hCursor := NumGet(ci, 8, "ptr") ; xCursor := NumGet(ci, 8+A_PtrSize, "int") ; yCursor := NumGet(ci, 12+A_PtrSize, "int") @@ -854,7 +854,7 @@ class ImagePut { ; pBits is the pointer to (top-down) pixel values. The Scan0 will point to the pBits. ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") - VarSetCapacity(bi, 40, 0) ; sizeof(bi) = 40 + VarSetCapacity(bi, 40, 0) ; sizeof(bi) = 40 NumPut( 40, bi, 0, "uint") ; Size NumPut( width, bi, 4, "uint") ; Width NumPut( -height, bi, 8, "int") ; Height - Negative so (0, 0) is top-left. @@ -868,10 +868,10 @@ class ImagePut { , "int", width, "int", height, "int", 0, "int", 0x26200A, "ptr", 0, "ptr*", pBitmap:=0) ; Create a Scan0 buffer pointing to pBits. The buffer has pixel format pARGB. - VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 + VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 NumPut( width, Rect, 8, "uint") ; Width NumPut( height, Rect, 12, "uint") ; Height - VarSetCapacity(BitmapData, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + VarSetCapacity(BitmapData, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 NumPut( width, BitmapData, 0, "uint") ; Width NumPut( height, BitmapData, 4, "uint") ; Height NumPut( 4 * width, BitmapData, 8, "int") ; Stride @@ -925,7 +925,7 @@ class ImagePut { ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") - VarSetCapacity(bi, 40, 0) ; sizeof(bi) = 40 + VarSetCapacity(bi, 40, 0) ; sizeof(bi) = 40 NumPut( 40, bi, 0, "uint") ; Size NumPut( width, bi, 4, "uint") ; Width NumPut( -height, bi, 8, "int") ; Height - Negative so (0, 0) is top-left. @@ -939,10 +939,10 @@ class ImagePut { , "int", width, "int", height, "int", 0, "int", 0x26200A, "ptr", 0, "ptr*", pBitmap:=0) ; Create a Scan0 buffer pointing to pBits. The buffer has pixel format pARGB. - VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 + VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 NumPut( width, Rect, 8, "uint") ; Width NumPut( height, Rect, 12, "uint") ; Height - VarSetCapacity(BitmapData, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + VarSetCapacity(BitmapData, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 NumPut( width, BitmapData, 0, "uint") ; Width NumPut( height, BitmapData, 4, "uint") ; Height NumPut( 4 * width, BitmapData, 8, "int") ; Stride @@ -1138,10 +1138,10 @@ class ImagePut { NumPut(0x000000FF, pdib+0, 48, "uint") ; Blue ; Transfer data from source pBitmap to the global memory manually. - VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 + VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 NumPut( width, Rect, 8, "uint") ; Width NumPut( height, Rect, 12, "uint") ; Height - VarSetCapacity(BitmapData, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + VarSetCapacity(BitmapData, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 NumPut( width, BitmapData, 0, "uint") ; Width NumPut( height, BitmapData, 4, "uint") ; Height NumPut( stride, BitmapData, 8, "int") ; Stride @@ -1253,7 +1253,7 @@ class ImagePut { ; struct tagWNDCLASSEXA - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexa ; struct tagWNDCLASSEXW - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexw - VarSetCapacity(WNDCLASSEX, size := A_PtrSize=8 ? 80:48, 0) ; sizeof(WNDCLASSEX) = 48 or 80 + VarSetCapacity(WNDCLASSEX, size := A_PtrSize=8 ? 80:48, 0) ; sizeof(WNDCLASSEX) = 48 or 80 NumPut( size, WNDCLASSEX, 0, "uint") ; cbSize NumPut( 0, WNDCLASSEX, 4, "uint") ; style NumPut( pWndProc, WNDCLASSEX, 8, "ptr") ; lpfnWndProc @@ -1264,7 +1264,7 @@ class ImagePut { NumPut( hCursor, WNDCLASSEX, A_PtrSize=8 ? 40:28, "ptr") ; hCursor NumPut( hBrush, WNDCLASSEX, A_PtrSize=8 ? 48:32, "ptr") ; hbrBackground NumPut( 0, WNDCLASSEX, A_PtrSize=8 ? 56:36, "ptr") ; lpszMenuName - NumPut( &class_name, WNDCLASSEX, A_PtrSize=8 ? 64:40, "ptr") ; lpszClassName + NumPut(&class_name, WNDCLASSEX, A_PtrSize=8 ? 64:40, "ptr") ; lpszClassName NumPut( 0, WNDCLASSEX, A_PtrSize=8 ? 72:44, "ptr") ; hIconSm ; Registers a window class for subsequent use in calls to the CreateWindow or CreateWindowEx function. @@ -1456,13 +1456,13 @@ class ImagePut { ; Sets the hotspot of the cursor by changing the icon into a cursor. if (xHotspot != "" || yHotspot != "") { ; struct ICONINFO - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-iconinfo - VarSetCapacity(ii, 8+3*A_PtrSize, 0) ; sizeof(ICONINFO) = 20, 32 - DllCall("GetIconInfo", "ptr", hIcon, "ptr", &ii) ; Fill the ICONINFO structure. + VarSetCapacity(ii, 8+3*A_PtrSize, 0) ; sizeof(ICONINFO) = 20, 32 + DllCall("GetIconInfo", "ptr", hIcon, "ptr", &ii) ; Fill the ICONINFO structure. NumPut(false, ii, 0, "uint") ; true/false are icon/cursor respectively. - , (xHotspot != "") ? NumPut(xHotspot, ii, 4, "uint") : "" ; Set the xHotspot value. (Default: center point) - , (yHotspot != "") ? NumPut(yHotspot, ii, 8, "uint") : "" ; Set the yHotspot value. (Default: center point) - DllCall("DestroyIcon", "ptr", hIcon) ; Destroy the icon after getting the ICONINFO structure. - hIcon := DllCall("CreateIconIndirect", "ptr", &ii, "ptr") ; Create a new cursor using ICONINFO. + (xHotspot != "") ? NumPut(xHotspot, ii, 4, "uint") : "" ; Set the xHotspot value. (Default: center point) + (yHotspot != "") ? NumPut(yHotspot, ii, 8, "uint") : "" ; Set the yHotspot value. (Default: center point) + DllCall("DestroyIcon", "ptr", hIcon) ; Destroy the icon after getting the ICONINFO structure. + hIcon := DllCall("CreateIconIndirect", "ptr", &ii, "ptr") ; Create a new cursor using ICONINFO. ; Clean up hbmMask and hbmColor created as a result of GetIconInfo. DllCall("DeleteObject", "ptr", NumGet(ii, 8+A_PtrSize, "ptr")) ; hbmMask @@ -1536,7 +1536,7 @@ class ImagePut { until (NumGet(EncoderParameters, elem+16, "uint") = 1) && (NumGet(EncoderParameters, elem+20, "uint") = 6) ; struct EncoderParameter - http://www.jose.it-berater.org/gdiplus/reference/structures/encoderparameter.htm - ep := &EncoderParameters + elem - A_PtrSize ; sizeof(EncoderParameter) = 28, 32 + ep := &EncoderParameters + elem - A_PtrSize ; sizeof(EncoderParameter) = 28, 32 NumPut( 1, ep+0, 0, "uptr") ; Must be 1. NumPut( 4, ep+0, 20+A_PtrSize, "uint") ; Type NumPut(quality, NumGet(ep+24+A_PtrSize, "uptr"), "uint") ; Value (pointer) @@ -1567,7 +1567,7 @@ class ImagePut { ; Convert the source pBitmap into a hBitmap manually. ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") - VarSetCapacity(bi, 40, 0) ; sizeof(bi) = 40 + VarSetCapacity(bi, 40, 0) ; sizeof(bi) = 40 NumPut( 40, bi, 0, "uint") ; Size NumPut( width, bi, 4, "uint") ; Width NumPut( -height, bi, 8, "int") ; Height - Negative so (0, 0) is top-left. @@ -1577,10 +1577,10 @@ class ImagePut { obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") ; Transfer data from source pBitmap to an hBitmap manually. - VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 + VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 NumPut( width, Rect, 8, "uint") ; Width NumPut( height, Rect, 12, "uint") ; Height - VarSetCapacity(BitmapData, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + VarSetCapacity(BitmapData, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 NumPut( width, BitmapData, 0, "uint") ; Width NumPut( height, BitmapData, 4, "uint") ; Height NumPut( 4 * width, BitmapData, 8, "int") ; Stride @@ -1640,7 +1640,7 @@ class ImagePut { until (NumGet(EncoderParameters, elem+16, "uint") = 1) && (NumGet(EncoderParameters, elem+20, "uint") = 6) ; struct EncoderParameter - http://www.jose.it-berater.org/gdiplus/reference/structures/encoderparameter.htm - ep := &EncoderParameters + elem - A_PtrSize ; sizeof(EncoderParameter) = 28, 32 + ep := &EncoderParameters + elem - A_PtrSize ; sizeof(EncoderParameter) = 28, 32 NumPut( 1, ep+0, 0, "uptr") ; Must be 1. NumPut( 4, ep+0, 20+A_PtrSize, "uint") ; Type NumPut(quality, NumGet(ep+24+A_PtrSize, "uptr"), "uint") ; Value (pointer) @@ -1842,7 +1842,7 @@ class ImageEqual extends ImagePut { return false ; struct RECT - https://docs.microsoft.com/en-us/windows/win32/api/windef/ns-windef-rect - VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 + VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 NumPut( Width1, Rect, 8, "uint") ; Width NumPut( Height1, Rect, 12, "uint") ; Height diff --git a/ImagePut.ahk b/ImagePut.ahk index 89e67313..e9d16508 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -622,7 +622,7 @@ class ImagePut { ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") - bi := Buffer(40, 0) ; sizeof(bi) = 40 + bi := Buffer(40, 0) ; sizeof(bi) = 40 NumPut( "uint", 40, bi, 0) ; Size NumPut( "int", image[3], bi, 4) ; Width NumPut( "int", -image[4], bi, 8) ; Height - Negative so (0, 0) is top-left. @@ -671,7 +671,7 @@ class ImagePut { ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") - bi := Buffer(40, 0) ; sizeof(bi) = 40 + bi := Buffer(40, 0) ; sizeof(bi) = 40 NumPut( "uint", 40, bi, 0) ; Size NumPut( "int", width, bi, 4) ; Width NumPut( "int", -height, bi, 8) ; Height - Negative so (0, 0) is top-left. @@ -720,7 +720,7 @@ class ImagePut { ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") - bi := Buffer(40, 0) ; sizeof(bi) = 40 + bi := Buffer(40, 0) ; sizeof(bi) = 40 NumPut( "uint", 40, bi, 0) ; Size NumPut( "int", width, bi, 4) ; Width NumPut( "int", -height, bi, 8) ; Height - Negative so (0, 0) is top-left. @@ -755,7 +755,7 @@ class ImagePut { ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") - bi := Buffer(40, 0) ; sizeof(bi) = 40 + bi := Buffer(40, 0) ; sizeof(bi) = 40 NumPut( "uint", 40, bi, 0) ; Size NumPut( "int", width, bi, 4) ; Width NumPut( "int", -height, bi, 8) ; Height - Negative so (0, 0) is top-left. @@ -854,7 +854,7 @@ class ImagePut { ; pBits is the pointer to (top-down) pixel values. The Scan0 will point to the pBits. ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") - bi := Buffer(40, 0) ; sizeof(bi) = 40 + bi := Buffer(40, 0) ; sizeof(bi) = 40 NumPut( "uint", 40, bi, 0) ; Size NumPut( "int", width, bi, 4) ; Width NumPut( "int", -height, bi, 8) ; Height - Negative so (0, 0) is top-left. @@ -868,10 +868,10 @@ class ImagePut { , "int", width, "int", height, "int", 0, "int", 0x26200A, "ptr", 0, "ptr*", &pBitmap:=0) ; Create a Scan0 buffer pointing to pBits. The buffer has pixel format pARGB. - Rect := Buffer(16, 0) ; sizeof(Rect) = 16 + Rect := Buffer(16, 0) ; sizeof(Rect) = 16 NumPut( "uint", width, Rect, 8) ; Width NumPut( "uint", height, Rect, 12) ; Height - BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 NumPut( "uint", width, BitmapData, 0) ; Width NumPut( "uint", height, BitmapData, 4) ; Height NumPut( "int", 4 * width, BitmapData, 8) ; Stride @@ -925,7 +925,7 @@ class ImagePut { ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") - bi := Buffer(40, 0) ; sizeof(bi) = 40 + bi := Buffer(40, 0) ; sizeof(bi) = 40 NumPut( "uint", 40, bi, 0) ; Size NumPut( "int", width, bi, 4) ; Width NumPut( "int", -height, bi, 8) ; Height - Negative so (0, 0) is top-left. @@ -939,10 +939,10 @@ class ImagePut { , "int", width, "int", height, "int", 0, "int", 0x26200A, "ptr", 0, "ptr*", &pBitmap:=0) ; Create a Scan0 buffer pointing to pBits. The buffer has pixel format pARGB. - Rect := Buffer(16, 0) ; sizeof(Rect) = 16 + Rect := Buffer(16, 0) ; sizeof(Rect) = 16 NumPut( "uint", width, Rect, 8) ; Width NumPut( "uint", height, Rect, 12) ; Height - BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 NumPut( "uint", width, BitmapData, 0) ; Width NumPut( "uint", height, BitmapData, 4) ; Height NumPut( "int", 4 * width, BitmapData, 8) ; Stride @@ -1138,10 +1138,10 @@ class ImagePut { NumPut( "uint", 0x000000FF, pdib, 48) ; Blue ; Transfer data from source pBitmap to the global memory manually. - Rect := Buffer(16, 0) ; sizeof(Rect) = 16 + Rect := Buffer(16, 0) ; sizeof(Rect) = 16 NumPut( "uint", width, Rect, 8) ; Width NumPut( "uint", height, Rect, 12) ; Height - BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 NumPut( "uint", width, BitmapData, 0) ; Width NumPut( "uint", height, BitmapData, 4) ; Height NumPut( "int", stride, BitmapData, 8) ; Stride @@ -1253,8 +1253,8 @@ class ImagePut { ; struct tagWNDCLASSEXA - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexa ; struct tagWNDCLASSEXW - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexw - WNDCLASSEX := Buffer(A_PtrSize=8 ? 80:48, 0) ; sizeof(WNDCLASSEX) = 48, 80 - NumPut( "uint", WNDCLASSEX.size, WNDCLASSEX, 0) ; cbSize + WNDCLASSEX := Buffer(A_PtrSize=8 ? 80:48, 0) ; sizeof(WNDCLASSEX) = 48, 80 + NumPut( "uint", WNDCLASSEX.size, WNDCLASSEX, 0) ; cbSize NumPut( "uint", 0, WNDCLASSEX, 4) ; style NumPut( "ptr", pWndProc, WNDCLASSEX, 8) ; lpfnWndProc NumPut( "int", 0, WNDCLASSEX, A_PtrSize=8 ? 16:12) ; cbClsExtra @@ -1456,13 +1456,13 @@ class ImagePut { ; Sets the hotspot of the cursor by changing the icon into a cursor. if (xHotspot != "" || yHotspot != "") { ; struct ICONINFO - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-iconinfo - ii := Buffer(8+3*A_PtrSize, 0) ; sizeof(ICONINFO) = 20, 32 - DllCall("GetIconInfo", "ptr", hIcon, "ptr", ii) ; Fill the ICONINFO structure. + ii := Buffer(8+3*A_PtrSize, 0) ; sizeof(ICONINFO) = 20, 32 + DllCall("GetIconInfo", "ptr", hIcon, "ptr", ii) ; Fill the ICONINFO structure. NumPut("uint", false, ii, 0) ; true/false are icon/cursor respectively. - , (xHotspot != "") ? NumPut("uint", xHotspot, ii, 4) : "" ; Set the xHotspot value. (Default: center point) - , (yHotspot != "") ? NumPut("uint", yHotspot, ii, 8) : "" ; Set the yHotspot value. (Default: center point) - DllCall("DestroyIcon", "ptr", hIcon) ; Destroy the icon after getting the ICONINFO structure. - hIcon := DllCall("CreateIconIndirect", "ptr", ii, "ptr") ; Create a new cursor using ICONINFO. + (xHotspot != "") ? NumPut("uint", xHotspot, ii, 4) : "" ; Set the xHotspot value. (Default: center point) + (yHotspot != "") ? NumPut("uint", yHotspot, ii, 8) : "" ; Set the yHotspot value. (Default: center point) + DllCall("DestroyIcon", "ptr", hIcon) ; Destroy the icon after getting the ICONINFO structure. + hIcon := DllCall("CreateIconIndirect", "ptr", ii, "ptr") ; Create a new cursor using ICONINFO. ; Clean up hbmMask and hbmColor created as a result of GetIconInfo. DllCall("DeleteObject", "ptr", NumGet(ii, 8+A_PtrSize, "ptr")) ; hbmMask @@ -1536,7 +1536,7 @@ class ImagePut { until (NumGet(EncoderParameters, elem+16, "uint") = 1) && (NumGet(EncoderParameters, elem+20, "uint") = 6) ; struct EncoderParameter - http://www.jose.it-berater.org/gdiplus/reference/structures/encoderparameter.htm - ep := EncoderParameters.ptr + elem - A_PtrSize ; sizeof(EncoderParameter) = 28, 32 + ep := EncoderParameters.ptr + elem - A_PtrSize ; sizeof(EncoderParameter) = 28, 32 NumPut( "uptr", 1, ep) ; Must be 1. NumPut( "uint", 4, ep, 20+A_PtrSize) ; Type NumPut( "uint", quality, NumGet(ep+24+A_PtrSize, "uptr")) ; Value (pointer) @@ -1567,7 +1567,7 @@ class ImagePut { ; Convert the source pBitmap into a hBitmap manually. ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") - bi := Buffer(40, 0) ; sizeof(bi) = 40 + bi := Buffer(40, 0) ; sizeof(bi) = 40 NumPut( "uint", 40, bi, 0) ; Size NumPut( "int", width, bi, 4) ; Width NumPut( "int", -height, bi, 8) ; Height - Negative so (0, 0) is top-left. @@ -1577,10 +1577,10 @@ class ImagePut { obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") ; Transfer data from source pBitmap to an hBitmap manually. - Rect := Buffer(16, 0) ; sizeof(Rect) = 16 + Rect := Buffer(16, 0) ; sizeof(Rect) = 16 NumPut( "uint", width, Rect, 8) ; Width NumPut( "uint", height, Rect, 12) ; Height - BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 NumPut( "uint", width, BitmapData, 0) ; Width NumPut( "uint", height, BitmapData, 4) ; Height NumPut( "int", 4 * width, BitmapData, 8) ; Stride @@ -1640,7 +1640,7 @@ class ImagePut { until (NumGet(EncoderParameters, elem+16, "uint") = 1) && (NumGet(EncoderParameters, elem+20, "uint") = 6) ; struct EncoderParameter - http://www.jose.it-berater.org/gdiplus/reference/structures/encoderparameter.htm - ep := EncoderParameters.ptr + elem - A_PtrSize ; sizeof(EncoderParameter) = 28, 32 + ep := EncoderParameters.ptr + elem - A_PtrSize ; sizeof(EncoderParameter) = 28, 32 NumPut( "uptr", 1, ep) ; Must be 1. NumPut( "uint", 4, ep, 20+A_PtrSize) ; Type NumPut( "uint", quality, NumGet(ep+24+A_PtrSize, "uptr")) ; Value (pointer) @@ -1842,7 +1842,7 @@ class ImageEqual extends ImagePut { return false ; struct RECT - https://docs.microsoft.com/en-us/windows/win32/api/windef/ns-windef-rect - Rect := Buffer(16, 0) ; sizeof(Rect) = 16 + Rect := Buffer(16, 0) ; sizeof(Rect) = 16 NumPut( "uint", Width1, Rect, 8) ; Width NumPut( "uint", Height1, Rect, 12) ; Height From 840c0381527851a6cd182fd883ce31801feeb938 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 17 May 2021 21:23:19 -0400 Subject: [PATCH 007/492] =?UTF-8?q?v2-a134=20HasOwnMethod=20=E2=86=92=20Ha?= =?UTF-8?q?sMethod?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ImagePut.ahk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index e9d16508..8a08103d 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -273,7 +273,7 @@ class ImagePut { return "clipboard" ; An "object" is an object that implements a Bitmap() method returning a pointer to a GDI+ bitmap. - if image.HasOwnMethod("Bitmap") + if image.HasMethod("Bitmap") return "object" ; A "buffer" is an AutoHotkey v2 buffer object. From 1a48c1798156a651a7f4899e24701c00213eef8f Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 17 May 2021 21:52:25 -0400 Subject: [PATCH 008/492] Simplify ImageEqual and standardize formatting --- ImagePut (for v1).ahk | 26 +++++++++++++------------- ImagePut.ahk | 26 +++++++++++++------------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index da890185..2f16e577 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1824,7 +1824,7 @@ class ImageEqual extends ImagePut { isBitmapEqual(ByRef pBitmap1, ByRef pBitmap2, Format := 0x26200A) { ; Make sure both bitmaps are valid pointers. - if !(pBitmap1 && pBitmap2) + if (!pBitmap1 || !pBitmap2) return false ; Check if pointers are identical. @@ -1832,22 +1832,22 @@ class ImageEqual extends ImagePut { return true ; The two bitmaps must be the same size. - DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap1, "uint*", Width1) - DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap2, "uint*", Width2) - DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap1, "uint*", Height1) - DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap2, "uint*", Height2) + DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap1, "uint*", width1:=0) + DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap2, "uint*", width2:=0) + DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap1, "uint*", height1:=0) + DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap2, "uint*", height2:=0) ; Match bitmap dimensions. - if (Width1 != Width2 || Height1 != Height2) + if (width1 != width2 || height1 != height2) return false ; struct RECT - https://docs.microsoft.com/en-us/windows/win32/api/windef/ns-windef-rect VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 - NumPut( Width1, Rect, 8, "uint") ; Width - NumPut( Height1, Rect, 12, "uint") ; Height + NumPut( width1, Rect, 8, "uint") ; Width + NumPut( height1, Rect, 12, "uint") ; Height ; Do this twice. - while ((i++:=i?i:0) < 2) { ; for(int i = 0; i < 2; i++) + while ((i++:=i?i:0) < 2) { ; for(int i = 1; i <= 2; i++) ; Create a BitmapData structure. VarSetCapacity(BitmapData%i%, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 @@ -1861,11 +1861,11 @@ class ImageEqual extends ImagePut { , "ptr", &BitmapData%i%) ; Get Stride (number of bytes per horizontal line). - Stride%i% := NumGet(BitmapData%i%, 8, "int") + stride%i% := NumGet(BitmapData%i%, 8, "int") ; If the Stride is negative, clone the image to make it top-down; redo the loop. - if (Stride%i% < 0) { - DllCall("gdiplus\GdipCloneImage", "ptr", pBitmap%i%, "ptr*", pBitmapClone) + if (stride%i% < 0) { + DllCall("gdiplus\GdipCloneImage", "ptr", pBitmap%i%, "ptr*", pBitmapClone:=0) DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap%i%) ; Permanently deletes. pBitmap%i% := pBitmapClone i-- ; "Let's go around again! Ha!" https://bit.ly/2AWWcM3 @@ -1876,7 +1876,7 @@ class ImageEqual extends ImagePut { } ; RtlCompareMemory preforms an unsafe comparison stopping at the first different byte. - size := Stride1 * Height1 + size := stride1 * height1 byte := DllCall("ntdll\RtlCompareMemory", "ptr", Scan01+0, "ptr", Scan02+0, "uptr", size, "uptr") ; Unlock Bitmaps. Since they were marked as read only there is no copy back. diff --git a/ImagePut.ahk b/ImagePut.ahk index 8a08103d..9994c37e 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1824,7 +1824,7 @@ class ImageEqual extends ImagePut { static isBitmapEqual(pBitmap1, pBitmap2, Format := 0x26200A) { ; Make sure both bitmaps are valid pointers. - if !(pBitmap1 && pBitmap2) + if (!pBitmap1 || !pBitmap2) return false ; Check if pointers are identical. @@ -1832,25 +1832,25 @@ class ImageEqual extends ImagePut { return true ; The two bitmaps must be the same size. - DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap1, "uint*", &Width1:=0) - DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap2, "uint*", &Width2:=0) - DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap1, "uint*", &Height1:=0) - DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap2, "uint*", &Height2:=0) + DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap1, "uint*", &width1:=0) + DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap2, "uint*", &width2:=0) + DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap1, "uint*", &height1:=0) + DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap2, "uint*", &height2:=0) ; Match bitmap dimensions. - if (Width1 != Width2 || Height1 != Height2) + if (width1 != width2 || height1 != height2) return false ; struct RECT - https://docs.microsoft.com/en-us/windows/win32/api/windef/ns-windef-rect Rect := Buffer(16, 0) ; sizeof(Rect) = 16 - NumPut( "uint", Width1, Rect, 8) ; Width - NumPut( "uint", Height1, Rect, 12) ; Height + NumPut( "uint", width1, Rect, 8) ; Width + NumPut( "uint", height1, Rect, 12) ; Height ; Do this twice. - while ((i:=IsSet(i)?i:0)++ < 2) { ; for(int i = 0; i < 2; i++) + while ((i:=IsSet(i)?i:0)++ < 2) { ; for(int i = 1; i <= 2; i++) ; Create a BitmapData structure. - BitmapData%i% := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + BitmapData%i% := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 ; Transfer the pixels to a read-only buffer. Avoid using a different PixelFormat. DllCall("gdiplus\GdipBitmapLockBits" @@ -1861,10 +1861,10 @@ class ImageEqual extends ImagePut { , "ptr", BitmapData%i%) ; Get Stride (number of bytes per horizontal line). - Stride%i% := NumGet(BitmapData%i%, 8, "int") + stride%i% := NumGet(BitmapData%i%, 8, "int") ; If the Stride is negative, clone the image to make it top-down; redo the loop. - if (Stride%i% < 0) { + if (stride%i% < 0) { DllCall("gdiplus\GdipCloneImage", "ptr", pBitmap%i%, "ptr*", &pBitmapClone:=0) DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap%i%) ; Permanently deletes. pBitmap%i% := pBitmapClone @@ -1876,7 +1876,7 @@ class ImageEqual extends ImagePut { } ; RtlCompareMemory preforms an unsafe comparison stopping at the first different byte. - size := Stride%'1'% * Height1 + size := stride%'1'% * height1 byte := DllCall("ntdll\RtlCompareMemory", "ptr", Scan0%'1'%, "ptr", Scan0%'2'%, "uptr", size, "uptr") ; Unlock Bitmaps. Since they were marked as read only there is no copy back. From 652f9dec001d0fdd95814b69dbdb390bb8c05588 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 21 May 2021 18:28:25 -0400 Subject: [PATCH 009/492] Remove unused parameters in BitmapData --- ImagePut (for v1).ahk | 20 ++++---------------- ImagePut.ahk | 12 ------------ 2 files changed, 4 insertions(+), 28 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 2f16e577..0d647bc4 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -268,7 +268,7 @@ class ImagePut { result := !DllCall("IsClipboardFormatAvailable", "uint", DllCall("RegisterClipboardFormat", "str", "png", "uint")) && !DllCall("IsClipboardFormatAvailable", "uint", 2) DllCall("CloseClipboard") if !(result) - return "clipboard" + return "clipboard" throw Exception("Image data is an empty string.") } if IsObject(image) { @@ -872,10 +872,7 @@ class ImagePut { NumPut( width, Rect, 8, "uint") ; Width NumPut( height, Rect, 12, "uint") ; Height VarSetCapacity(BitmapData, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 - NumPut( width, BitmapData, 0, "uint") ; Width - NumPut( height, BitmapData, 4, "uint") ; Height NumPut( 4 * width, BitmapData, 8, "int") ; Stride - NumPut( 0xE200B, BitmapData, 12, "int") ; PixelFormat NumPut( pBits, BitmapData, 16, "ptr") ; Scan0 ; Use LockBits to create a writable buffer that converts pARGB to ARGB. @@ -943,10 +940,7 @@ class ImagePut { NumPut( width, Rect, 8, "uint") ; Width NumPut( height, Rect, 12, "uint") ; Height VarSetCapacity(BitmapData, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 - NumPut( width, BitmapData, 0, "uint") ; Width - NumPut( height, BitmapData, 4, "uint") ; Height NumPut( 4 * width, BitmapData, 8, "int") ; Stride - NumPut( 0xE200B, BitmapData, 12, "int") ; PixelFormat NumPut( pBits, BitmapData, 16, "ptr") ; Scan0 ; Use LockBits to create a writable buffer that converts pARGB to ARGB. @@ -1142,10 +1136,7 @@ class ImagePut { NumPut( width, Rect, 8, "uint") ; Width NumPut( height, Rect, 12, "uint") ; Height VarSetCapacity(BitmapData, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 - NumPut( width, BitmapData, 0, "uint") ; Width - NumPut( height, BitmapData, 4, "uint") ; Height NumPut( stride, BitmapData, 8, "int") ; Stride - NumPut( format, BitmapData, 12, "int") ; PixelFormat NumPut( pdib + 52, BitmapData, 16, "ptr") ; Scan0 DllCall("gdiplus\GdipBitmapLockBits" , "ptr", pBitmap @@ -1230,7 +1221,7 @@ class ImagePut { } put_window(ByRef pBitmap, title := "") { - ; Make it permanent. + ; Make it permanent. void := ObjBindMethod({}, {}) Hotkey % "^+F12", % void, On @@ -1288,7 +1279,7 @@ class ImagePut { WS_EX_TRANSPARENT := 0x20 WS_EX_DLGMODALFRAME := 0x1 - VarSetCapacity(rect, 16, 0) + VarSetCapacity(rect, 16, 0) NumPut(Floor((A_ScreenWidth - width) / 2), rect, 0, "int") NumPut(Floor((A_ScreenHeight - height) / 2), rect, 4, "int") NumPut(Floor((A_ScreenWidth + width) / 2), rect, 8, "int") @@ -1581,10 +1572,7 @@ class ImagePut { NumPut( width, Rect, 8, "uint") ; Width NumPut( height, Rect, 12, "uint") ; Height VarSetCapacity(BitmapData, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 - NumPut( width, BitmapData, 0, "uint") ; Width - NumPut( height, BitmapData, 4, "uint") ; Height NumPut( 4 * width, BitmapData, 8, "int") ; Stride - NumPut( 0xE200B, BitmapData, 12, "int") ; PixelFormat NumPut( pBits, BitmapData, 16, "ptr") ; Scan0 DllCall("gdiplus\GdipBitmapLockBits" , "ptr", pBitmap @@ -1746,7 +1734,7 @@ class ImagePut { if DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) throw Exception("The bitmap of this buffer object has already been deleted.") - ; Check for unpaired calls of gdiplusShutdown. + ; Check for unpaired calls of gdiplusShutdown. if (ImagePut.gdiplus < 0) throw Exception("Missing ImagePut.gdiplusStartup().") diff --git a/ImagePut.ahk b/ImagePut.ahk index 9994c37e..3c376370 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -872,10 +872,7 @@ class ImagePut { NumPut( "uint", width, Rect, 8) ; Width NumPut( "uint", height, Rect, 12) ; Height BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 - NumPut( "uint", width, BitmapData, 0) ; Width - NumPut( "uint", height, BitmapData, 4) ; Height NumPut( "int", 4 * width, BitmapData, 8) ; Stride - NumPut( "int", 0xE200B, BitmapData, 12) ; PixelFormat NumPut( "ptr", pBits, BitmapData, 16) ; Scan0 ; Use LockBits to create a writable buffer that converts pARGB to ARGB. @@ -943,10 +940,7 @@ class ImagePut { NumPut( "uint", width, Rect, 8) ; Width NumPut( "uint", height, Rect, 12) ; Height BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 - NumPut( "uint", width, BitmapData, 0) ; Width - NumPut( "uint", height, BitmapData, 4) ; Height NumPut( "int", 4 * width, BitmapData, 8) ; Stride - NumPut( "int", 0xE200B, BitmapData, 12) ; PixelFormat NumPut( "ptr", pBits, BitmapData, 16) ; Scan0 ; Use LockBits to create a writable buffer that converts pARGB to ARGB. @@ -1142,10 +1136,7 @@ class ImagePut { NumPut( "uint", width, Rect, 8) ; Width NumPut( "uint", height, Rect, 12) ; Height BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 - NumPut( "uint", width, BitmapData, 0) ; Width - NumPut( "uint", height, BitmapData, 4) ; Height NumPut( "int", stride, BitmapData, 8) ; Stride - NumPut( "int", format, BitmapData, 12) ; PixelFormat NumPut( "ptr", pdib + 52, BitmapData, 16) ; Scan0 DllCall("gdiplus\GdipBitmapLockBits" , "ptr", pBitmap @@ -1581,10 +1572,7 @@ class ImagePut { NumPut( "uint", width, Rect, 8) ; Width NumPut( "uint", height, Rect, 12) ; Height BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 - NumPut( "uint", width, BitmapData, 0) ; Width - NumPut( "uint", height, BitmapData, 4) ; Height NumPut( "int", 4 * width, BitmapData, 8) ; Stride - NumPut( "int", 0xE200B, BitmapData, 12) ; PixelFormat NumPut( "ptr", pBits, BitmapData, 16) ; Scan0 DllCall("gdiplus\GdipBitmapLockBits" , "ptr", pBitmap From 228be8e7b78b68ce27c9b981bb456d11ce9e3a3e Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 25 Sep 2021 19:16:26 -0400 Subject: [PATCH 010/492] Reverse order of A_PtrSize = 8 to A_PtrSize = 4 --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 0d647bc4..c9ab4d66 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1718,7 +1718,7 @@ class ImagePut { ; Startup gdiplus. DllCall("LoadLibrary", "str", "gdiplus") - VarSetCapacity(si, A_PtrSize = 8 ? 24 : 16, 0) ; sizeof(GdiplusStartupInput) = 16, 24 + VarSetCapacity(si, A_PtrSize = 4 ? 16:24, 0) ; sizeof(GdiplusStartupInput) = 16, 24 NumPut(0x1, si, "uint") DllCall("gdiplus\GdiplusStartup", "ptr*", pToken:=0, "ptr", &si, "ptr", 0) diff --git a/ImagePut.ahk b/ImagePut.ahk index 3c376370..8fd58341 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1718,7 +1718,7 @@ class ImagePut { ; Startup gdiplus. DllCall("LoadLibrary", "str", "gdiplus") - si := Buffer(A_PtrSize = 8 ? 24 : 16, 0) ; sizeof(GdiplusStartupInput) = 16, 24 + si := Buffer(A_PtrSize = 4 ? 16:24, 0) ; sizeof(GdiplusStartupInput) = 16, 24 NumPut("uint", 0x1, si) DllCall("gdiplus\GdiplusStartup", "ptr*", &pToken:=0, "ptr", si, "ptr", 0) From 07189a858896cc9e1e71bc42b64e7018dc285f5f Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 25 Sep 2021 19:19:29 -0400 Subject: [PATCH 011/492] Remove ByRef from pBitmap --- ImagePut (for v1).ahk | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index c9ab4d66..7ad18e3a 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -418,7 +418,7 @@ class ImagePut { throw Exception("Conversion from type " type " is not supported.") } - toCotype(cotype, ByRef pBitmap, term1 := "", term2 := "", _*) { + toCotype(cotype, pBitmap, term1 := "", term2 := "", _*) { ; toCotype("clipboard", pBitmap) if (cotype = "clipboard") return this.put_clipboard(pBitmap) @@ -486,11 +486,11 @@ class ImagePut { throw Exception("Conversion to type " cotype " is not supported.") } - DisposeImage(ByRef pBitmap) { + DisposeImage(pBitmap) { return DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) } - BitmapCrop(ByRef pBitmap, crop) { + BitmapCrop(pBitmap, crop) { ; Get Bitmap width, height, and format. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) @@ -536,7 +536,7 @@ class ImagePut { return pBitmapCrop } - BitmapScale(ByRef pBitmap, scale) { + BitmapScale(pBitmap, scale) { ; Get Bitmap width, height, and format. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) @@ -1080,7 +1080,7 @@ class ImagePut { return dBitmap } - put_clipboard(ByRef pBitmap) { + put_clipboard(pBitmap) { ; Standard Clipboard Formats - https://docs.microsoft.com/en-us/windows/win32/dataxchg/standard-clipboard-formats ; Synthesized Clipboard Formats - https://docs.microsoft.com/en-us/windows/win32/dataxchg/clipboard-formats @@ -1158,7 +1158,7 @@ class ImagePut { return "" } - put_buffer(ByRef pBitmap) { + put_buffer(pBitmap) { buffer := {__New: ObjBindMethod(this, "gdiplusStartup") ; Increment GDI+ reference count , __Delete: ObjBindMethod(this, "gdiplusShutdown", "smart_pointer", pBitmap)} buffer := new buffer ; On deletion the buffer object will dispose of the bitmap. @@ -1166,7 +1166,7 @@ class ImagePut { return buffer } - put_screenshot(ByRef pBitmap, screenshot := "", alpha := "") { + put_screenshot(pBitmap, screenshot := "", alpha := "") { ; Get Bitmap width and height. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) @@ -1220,7 +1220,7 @@ class ImagePut { return DllCall("DefWindowProc", "ptr", hwnd, "uint", uMsg, "uptr", wParam, "ptr", lParam, "ptr") } - put_window(ByRef pBitmap, title := "") { + put_window(pBitmap, title := "") { ; Make it permanent. void := ObjBindMethod({}, {}) Hotkey % "^+F12", % void, On @@ -1360,7 +1360,7 @@ class ImagePut { return hwnd0 } - put_desktop(ByRef pBitmap) { + put_desktop(pBitmap) { ; Thanks Gerald Degeneve - https://www.codeproject.com/Articles/856020/Draw-Behind-Desktop-Icons-in-Windows-plus ; Get Bitmap width and height. @@ -1411,7 +1411,7 @@ class ImagePut { return "desktop" } - put_wallpaper(ByRef pBitmap) { + put_wallpaper(pBitmap) { ; Create a temporary image file. filepath := this.put_file(pBitmap) @@ -1438,7 +1438,7 @@ class ImagePut { return "wallpaper" } - put_cursor(ByRef pBitmap, xHotspot := "", yHotspot := "") { + put_cursor(pBitmap, xHotspot := "", yHotspot := "") { ; Thanks Nick - https://stackoverflow.com/a/550965 ; Creates an icon that can be used as a cursor. @@ -1475,7 +1475,7 @@ class ImagePut { return "A_Cursor" } - put_file(ByRef pBitmap, filepath := "", quality := "") { + put_file(pBitmap, filepath := "", quality := "") { ; Thanks tic - https://www.autohotkey.com/boards/viewtopic.php?t=6517 ; Remove whitespace. Seperate the filepath. Adjust for directories. @@ -1544,7 +1544,7 @@ class ImagePut { return filepath } - put_hBitmap(ByRef pBitmap, alpha := "") { + put_hBitmap(pBitmap, alpha := "") { ; Revert to built in functionality if a replacement color is declared. if (alpha != "") { ; This built-in version is about 25% slower. DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", "ptr", pBitmap, "ptr*", hBitmap:=0, "uint", alpha) @@ -1589,12 +1589,12 @@ class ImagePut { return hbm } - put_hIcon(ByRef pBitmap) { + put_hIcon(pBitmap) { DllCall("gdiplus\GdipCreateHICONFromBitmap", "ptr", pBitmap, "ptr*", hIcon:=0) return hIcon } - put_stream(ByRef pBitmap, extension := "", quality := "") { + put_stream(pBitmap, extension := "", quality := "") { ; Default extension is TIF for fast speeds! if !(extension ~= "^(?i:bmp|dib|rle|jpg|jpeg|jpe|jfif|gif|tif|tiff|png)$") extension := "tif" @@ -1641,7 +1641,7 @@ class ImagePut { return pStream } - put_RandomAccessStream(ByRef pBitmap, extension := "", quality := "") { + put_RandomAccessStream(pBitmap, extension := "", quality := "") { ; Thanks teadrinker - https://www.autohotkey.com/boards/viewtopic.php?f=6&t=72674 ; Which is faster, bmp or png? @@ -1661,7 +1661,7 @@ class ImagePut { return pRandomAccessStream } - put_hex(ByRef pBitmap, extension := "", quality := "") { + put_hex(pBitmap, extension := "", quality := "") { ; Default extension is PNG for small sizes! if !(extension ~= "^(?i:bmp|dib|rle|jpg|jpeg|jpe|jfif|gif|tif|tiff|png)$") extension := "png" @@ -1683,7 +1683,7 @@ class ImagePut { return StrGet(&hex, length, "CP0") } - put_base64(ByRef pBitmap, extension := "", quality := "") { + put_base64(pBitmap, extension := "", quality := "") { ; Thanks noname - https://www.autohotkey.com/boards/viewtopic.php?style=7&p=144247#p144247 ; Default extension is PNG for small sizes! @@ -1726,7 +1726,7 @@ class ImagePut { } } - gdiplusShutdown(cotype := "", ByRef pBitmap := "") { + gdiplusShutdown(cotype := "", pBitmap := "") { ImagePut.gdiplus-- ; When a buffer object is deleted a bitmap is sent here for disposal. @@ -1810,7 +1810,7 @@ class ImageEqual extends ImagePut { return result } - isBitmapEqual(ByRef pBitmap1, ByRef pBitmap2, Format := 0x26200A) { + isBitmapEqual(pBitmap1, pBitmap2, Format := 0x26200A) { ; Make sure both bitmaps are valid pointers. if (!pBitmap1 || !pBitmap2) return false From 948d169913383812c23f04b5e02a2e5a8f8748c0 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 25 Sep 2021 19:46:10 -0400 Subject: [PATCH 012/492] Rename WNDCLASSEX to wc --- ImagePut (for v1).ahk | 31 ++++++++++++++++--------------- ImagePut.ahk | 31 ++++++++++++++++--------------- 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 7ad18e3a..5e462b08 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1229,7 +1229,7 @@ class ImagePut { DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) - class_name := "ImagePut" + cls := this.__class pWndProc := RegisterCallback(this.WindowProc, "Fast",, &this) hCursor := DllCall("LoadCursor", "ptr", 0, "ptr", 32512, "ptr") ; IDC_ARROW @@ -1244,22 +1244,23 @@ class ImagePut { ; struct tagWNDCLASSEXA - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexa ; struct tagWNDCLASSEXW - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexw - VarSetCapacity(WNDCLASSEX, size := A_PtrSize=8 ? 80:48, 0) ; sizeof(WNDCLASSEX) = 48 or 80 - NumPut( size, WNDCLASSEX, 0, "uint") ; cbSize - NumPut( 0, WNDCLASSEX, 4, "uint") ; style - NumPut( pWndProc, WNDCLASSEX, 8, "ptr") ; lpfnWndProc - NumPut( 0, WNDCLASSEX, A_PtrSize=8 ? 16:12, "int") ; cbClsExtra - NumPut( 0, WNDCLASSEX, A_PtrSize=8 ? 20:16, "int") ; cbWndExtra - NumPut( 0, WNDCLASSEX, A_PtrSize=8 ? 24:20, "ptr") ; hInstance - NumPut( 0, WNDCLASSEX, A_PtrSize=8 ? 32:24, "ptr") ; hIcon - NumPut( hCursor, WNDCLASSEX, A_PtrSize=8 ? 40:28, "ptr") ; hCursor - NumPut( hBrush, WNDCLASSEX, A_PtrSize=8 ? 48:32, "ptr") ; hbrBackground - NumPut( 0, WNDCLASSEX, A_PtrSize=8 ? 56:36, "ptr") ; lpszMenuName - NumPut(&class_name, WNDCLASSEX, A_PtrSize=8 ? 64:40, "ptr") ; lpszClassName - NumPut( 0, WNDCLASSEX, A_PtrSize=8 ? 72:44, "ptr") ; hIconSm + _ := (A_PtrSize = 4) + VarSetCapacity(wc, size := _ ? 48:80, 0) ; sizeof(WNDCLASSEX) = 48, 80 + NumPut( size, wc, 0, "uint") ; cbSize + NumPut( 0, wc, 4, "uint") ; style + NumPut( pWndProc, wc, 8, "ptr") ; lpfnWndProc + NumPut( 0, wc, _ ? 12:16, "int") ; cbClsExtra + NumPut( 0, wc, _ ? 16:20, "int") ; cbWndExtra + NumPut( 0, wc, _ ? 20:24, "ptr") ; hInstance + NumPut( 0, wc, _ ? 24:32, "ptr") ; hIcon + NumPut( hCursor, wc, _ ? 28:40, "ptr") ; hCursor + NumPut( hBrush, wc, _ ? 32:48, "ptr") ; hbrBackground + NumPut( 0, wc, _ ? 36:56, "ptr") ; lpszMenuName + NumPut( &cls, wc, _ ? 40:64, "ptr") ; lpszClassName + NumPut( 0, wc, _ ? 44:72, "ptr") ; hIconSm ; Registers a window class for subsequent use in calls to the CreateWindow or CreateWindowEx function. - DllCall("RegisterClassEx", "ptr", &WNDCLASSEX, "ushort") + DllCall("RegisterClassEx", "ptr", &wc, "ushort") WS_VISIBLE := 0x10000000 WS_SYSMENU := 0x80000 diff --git a/ImagePut.ahk b/ImagePut.ahk index 8fd58341..66d54f66 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1229,7 +1229,7 @@ class ImagePut { DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) - class_name := "ImagePut" + cls := this.prototype.__class pWndProc := CallbackCreate(WindowProc, "Fast") hCursor := DllCall("LoadCursor", "ptr", 0, "ptr", 32512, "ptr") ; IDC_ARROW @@ -1244,22 +1244,23 @@ class ImagePut { ; struct tagWNDCLASSEXA - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexa ; struct tagWNDCLASSEXW - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexw - WNDCLASSEX := Buffer(A_PtrSize=8 ? 80:48, 0) ; sizeof(WNDCLASSEX) = 48, 80 - NumPut( "uint", WNDCLASSEX.size, WNDCLASSEX, 0) ; cbSize - NumPut( "uint", 0, WNDCLASSEX, 4) ; style - NumPut( "ptr", pWndProc, WNDCLASSEX, 8) ; lpfnWndProc - NumPut( "int", 0, WNDCLASSEX, A_PtrSize=8 ? 16:12) ; cbClsExtra - NumPut( "int", 0, WNDCLASSEX, A_PtrSize=8 ? 20:16) ; cbWndExtra - NumPut( "ptr", 0, WNDCLASSEX, A_PtrSize=8 ? 24:20) ; hInstance - NumPut( "ptr", 0, WNDCLASSEX, A_PtrSize=8 ? 32:24) ; hIcon - NumPut( "ptr", hCursor, WNDCLASSEX, A_PtrSize=8 ? 40:28) ; hCursor - NumPut( "ptr", hBrush, WNDCLASSEX, A_PtrSize=8 ? 48:32) ; hbrBackground - NumPut( "ptr", 0, WNDCLASSEX, A_PtrSize=8 ? 56:36) ; lpszMenuName - NumPut( "ptr", StrPtr(class_name), WNDCLASSEX, A_PtrSize=8 ? 64:40) ; lpszClassName - NumPut( "ptr", 0, WNDCLASSEX, A_PtrSize=8 ? 72:44) ; hIconSm + _ := (A_PtrSize = 4) + wc := Buffer(_ ? 48:80, 0) ; sizeof(WNDCLASSEX) = 48, 80 + NumPut( "uint", wc.size, wc, 0) ; cbSize + NumPut( "uint", 0, wc, 4) ; style + NumPut( "ptr", pWndProc, wc, 8) ; lpfnWndProc + NumPut( "int", 0, wc, _ ? 12:16) ; cbClsExtra + NumPut( "int", 0, wc, _ ? 16:20) ; cbWndExtra + NumPut( "ptr", 0, wc, _ ? 20:24) ; hInstance + NumPut( "ptr", 0, wc, _ ? 24:32) ; hIcon + NumPut( "ptr", hCursor, wc, _ ? 28:40) ; hCursor + NumPut( "ptr", hBrush, wc, _ ? 32:48) ; hbrBackground + NumPut( "ptr", 0, wc, _ ? 36:56) ; lpszMenuName + NumPut( "ptr", StrPtr(cls), wc, _ ? 40:64) ; lpszClassName + NumPut( "ptr", 0, wc, _ ? 44:72) ; hIconSm ; Registers a window class for subsequent use in calls to the CreateWindow or CreateWindowEx function. - DllCall("RegisterClassEx", "ptr", WNDCLASSEX, "ushort") + DllCall("RegisterClassEx", "ptr", wc, "ushort") WS_VISIBLE := 0x10000000 WS_SYSMENU := 0x80000 From 19e1182669573d4f90cd7142abb96b9aed09304f Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 25 Sep 2021 20:37:25 -0400 Subject: [PATCH 013/492] Update persistent in put_window --- ImagePut (for v1).ahk | 3 +-- ImagePut.ahk | 7 +++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 5e462b08..2280829d 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1206,8 +1206,7 @@ class ImagePut { ; WM_DESTROY if (uMsg = 0x2) { - ; MsgBox "NICE TRY! LOL!" - ; return + Hotkey % "^+F12", Off } ; WM_LBUTTONDOWN diff --git a/ImagePut.ahk b/ImagePut.ahk index 66d54f66..4f4ed2ca 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1207,8 +1207,7 @@ class ImagePut { ; WM_DESTROY if (uMsg = 0x2) { - ; MsgBox "NICE TRY! LOL!" - ; return + return Persistent(false) } ; WM_LBUTTONDOWN @@ -1222,8 +1221,8 @@ class ImagePut { } ; Make it permanent. - void := ObjBindMethod({}, {}) - Hotkey "^+F12", void, "On" + Persistent(true) + ; Get Bitmap width and height. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) From 62a0f71b1c8f3018ce8468a0f7f5382bc4e1de8e Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 25 Sep 2021 20:39:22 -0400 Subject: [PATCH 014/492] Remove fast mode from CallbackCreate for persistence --- ImagePut.ahk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index 4f4ed2ca..5605c55f 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1229,7 +1229,7 @@ class ImagePut { DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) cls := this.prototype.__class - pWndProc := CallbackCreate(WindowProc, "Fast") + pWndProc := CallbackCreate(WindowProc) hCursor := DllCall("LoadCursor", "ptr", 0, "ptr", 32512, "ptr") ; IDC_ARROW ;hBrush := DllCall("CreateSolidBrush", "uint", 0x00F0F0F0, "ptr") From 7a58c1b5cfbc99845140506dd400149a59f69da1 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 25 Sep 2021 20:42:03 -0400 Subject: [PATCH 015/492] Call DefWindowProc directly without PostMessage --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 2280829d..0221cf40 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1213,7 +1213,7 @@ class ImagePut { if (uMsg = 0x201) { parent := DllCall("GetParent", "ptr", hwnd, "ptr") hwnd := (parent != A_ScriptHwnd && parent != 0) ? parent : hwnd - PostMessage 0xA1, 2,,, % "ahk_id" hwnd + return DllCall("DefWindowProc", "ptr", hwnd, "uint", 0xA1, "uptr", 2, "ptr", 0, "ptr") } return DllCall("DefWindowProc", "ptr", hwnd, "uint", uMsg, "uptr", wParam, "ptr", lParam, "ptr") diff --git a/ImagePut.ahk b/ImagePut.ahk index 5605c55f..f49b1b73 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1214,7 +1214,7 @@ class ImagePut { if (uMsg = 0x201) { parent := DllCall("GetParent", "ptr", hwnd, "ptr") hwnd := (parent != A_ScriptHwnd && parent != 0) ? parent : hwnd - PostMessage 0xA1, 2,,, hwnd + return DllCall("DefWindowProc", "ptr", hwnd, "uint", 0xA1, "uptr", 2, "ptr", 0, "ptr") } return DllCall("DefWindowProc", "ptr", hwnd, "uint", uMsg, "uptr", wParam, "ptr", lParam, "ptr") From 52657f8231edcd5101911cd476ab3d2a1362786d Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 25 Sep 2021 21:13:50 -0400 Subject: [PATCH 016/492] Update logic flow for exponential backoff --- ImagePut (for v1).ahk | 58 +++++++++++++++++++++++-------------------- ImagePut.ahk | 58 +++++++++++++++++++++++-------------------- 2 files changed, 62 insertions(+), 54 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 0221cf40..09f7063a 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -589,13 +589,14 @@ class ImagePut { } from_clipboard() { - ; Open the clipboard. - Loop 6 ; Try this 6 times. - if (A_Index > 1) - Sleep % (2**(A_Index-2) * 30) - until (result := DllCall("OpenClipboard", "ptr", 0)) - if !(result) - throw Exception("Clipboard could not be opened.") + ; Open the clipboard with exponential backoff. + loop + if DllCall("OpenClipboard", "ptr", 0) + break + else + if A_Index < 6 + Sleep (2**(A_Index-1) * 30) + else throw Exception("Clipboard could not be opened.") ; Prefer the PNG stream if available considering it supports transparency. png := DllCall("RegisterClipboardFormat", "str", "png", "uint") @@ -1084,13 +1085,14 @@ class ImagePut { ; Standard Clipboard Formats - https://docs.microsoft.com/en-us/windows/win32/dataxchg/standard-clipboard-formats ; Synthesized Clipboard Formats - https://docs.microsoft.com/en-us/windows/win32/dataxchg/clipboard-formats - ; Open the clipboard. - Loop 6 ; Try this 6 times. - if (A_Index > 1) - Sleep % (2**(A_Index-2) * 30) - until (result := DllCall("OpenClipboard", "ptr", 0)) - if !(result) - throw Exception("Clipboard could not be opened.") + ; Open the clipboard with exponential backoff. + loop + if DllCall("OpenClipboard", "ptr", 0) + break + else + if A_Index < 6 + Sleep (2**(A_Index-1) * 30) + else throw Exception("Clipboard could not be opened.") ; Clear the clipboard. DllCall("EmptyClipboard") @@ -1421,12 +1423,13 @@ class ImagePut { DllCall("GetFullPathName", "str", filepath, "uint", length, "str", buf, "ptr", 0, "uint") ; Keep waiting until the file has been created. (It should be instant!) - Loop 6 ; Try this 6 times. - if (A_Index > 1) - Sleep % (2**(A_Index-2) * 30) - until FileExist(filepath) - if !FileExist(filepath) - throw Exception("Unable to create temporary image file.") + loop + if FileExist(filepath) + break + else + if A_Index < 6 + Sleep (2**(A_Index-1) * 30) + else throw Exception("Unable to create temporary image file.") ; Set the temporary image file as the new desktop wallpaper. DllCall("SystemParametersInfo", "uint", 20, "uint", 0, "str", buf, "uint", 2) @@ -1533,13 +1536,14 @@ class ImagePut { NumPut(quality, NumGet(ep+24+A_PtrSize, "uptr"), "uint") ; Value (pointer) } - ; Write the file to disk using the specified encoder and encoding parameters. - Loop 6 ; Try this 6 times. - if (A_Index > 1) - Sleep % (2**(A_Index-2) * 30) - until (result := !DllCall("gdiplus\GdipSaveImageToFile", "ptr", pBitmap, "wstr", filepath, "ptr", pCodec, "uint", (ep) ? ep : 0)) - if !(result) - throw Exception("Could not save file to disk.") + ; Write the file to disk using the specified encoder and encoding parameters with exponential backoff. + loop + if !DllCall("gdiplus\GdipSaveImageToFile", "ptr", pBitmap, "wstr", filepath, "ptr", pCodec, "uint", (ep) ? ep : 0) + break + else + if A_Index < 6 + Sleep (2**(A_Index-1) * 30) + else throw Exception("Could not save file to disk.") return filepath } diff --git a/ImagePut.ahk b/ImagePut.ahk index f49b1b73..a5da2dff 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -589,13 +589,14 @@ class ImagePut { } static from_clipboard() { - ; Open the clipboard. - Loop 6 ; Try this 6 times. - if (A_Index > 1) - Sleep (2**(A_Index-2) * 30) - until (result := DllCall("OpenClipboard", "ptr", 0)) - if !(result) - throw Error("Clipboard could not be opened.") + ; Open the clipboard with exponential backoff. + loop + if DllCall("OpenClipboard", "ptr", 0) + break + else + if A_Index < 6 + Sleep (2**(A_Index-1) * 30) + else throw Error("Clipboard could not be opened.") ; Prefer the PNG stream if available considering it supports transparency. png := DllCall("RegisterClipboardFormat", "str", "png", "uint") @@ -1084,13 +1085,14 @@ class ImagePut { ; Standard Clipboard Formats - https://docs.microsoft.com/en-us/windows/win32/dataxchg/standard-clipboard-formats ; Synthesized Clipboard Formats - https://docs.microsoft.com/en-us/windows/win32/dataxchg/clipboard-formats - ; Open the clipboard. - Loop 6 ; Try this 6 times. - if (A_Index > 1) - Sleep (2**(A_Index-2) * 30) - until (result := DllCall("OpenClipboard", "ptr", 0)) - if !(result) - throw Error("Clipboard could not be opened.") + ; Open the clipboard with exponential backoff. + loop + if DllCall("OpenClipboard", "ptr", 0) + break + else + if A_Index < 6 + Sleep (2**(A_Index-1) * 30) + else throw Error("Clipboard could not be opened.") ; Clear the clipboard. DllCall("EmptyClipboard") @@ -1421,12 +1423,13 @@ class ImagePut { DllCall("GetFullPathName", "str", filepath, "uint", length, "str", buf, "ptr", 0, "uint") ; Keep waiting until the file has been created. (It should be instant!) - Loop 6 ; Try this 6 times. - if (A_Index > 1) - Sleep (2**(A_Index-2) * 30) - until FileExist(filepath) - if !FileExist(filepath) - throw Error("Unable to create temporary image file.") + loop + if FileExist(filepath) + break + else + if A_Index < 6 + Sleep (2**(A_Index-1) * 30) + else throw Error("Unable to create temporary image file.") ; Set the temporary image file as the new desktop wallpaper. DllCall("SystemParametersInfo", "uint", 20, "uint", 0, "str", buf, "uint", 2) @@ -1533,13 +1536,14 @@ class ImagePut { NumPut( "uint", quality, NumGet(ep+24+A_PtrSize, "uptr")) ; Value (pointer) } - ; Write the file to disk using the specified encoder and encoding parameters. - Loop 6 ; Try this 6 times. - if (A_Index > 1) - Sleep (2**(A_Index-2) * 30) - until (result := !DllCall("gdiplus\GdipSaveImageToFile", "ptr", pBitmap, "wstr", filepath, "ptr", pCodec, "uint", IsSet(ep) ? ep : 0)) - if !(result) - throw Error("Could not save file to disk.") + ; Write the file to disk using the specified encoder and encoding parameters with exponential backoff. + loop + if !DllCall("gdiplus\GdipSaveImageToFile", "ptr", pBitmap, "wstr", filepath, "ptr", pCodec, "uint", IsSet(ep) ? ep : 0) + break + else + if A_Index < 6 + Sleep (2**(A_Index-1) * 30) + else throw Error("Could not save file to disk.") return filepath } From 9b6a35b003772d9d3183a67dacc9795fb47571c1 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 25 Sep 2021 22:21:44 -0400 Subject: [PATCH 017/492] File name collisions will now increment (1) --- ImagePut (for v1).ahk | 7 +++++++ ImagePut.ahk | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 09f7063a..67cd785a 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1501,6 +1501,13 @@ class ImagePut { FormatTime, filename,, % "yyyy-MM-dd HH?mm?ss" filepath := directory "\" filename "." extension + ; Check for collisions. + if FileExist(filepath) { + loop + filepath := directory "\" filename " (" A_Index ")." extension + until !FileExist(filepath) + } + ; Fill a buffer with the available encoders. DllCall("gdiplus\GdipGetImageEncodersSize", "uint*", count:=0, "uint*", size:=0) VarSetCapacity(ci, size) diff --git a/ImagePut.ahk b/ImagePut.ahk index a5da2dff..04c83deb 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1501,6 +1501,13 @@ class ImagePut { filename := FormatTime(, "yyyy-MM-dd HH?mm?ss") filepath := directory "\" filename "." extension + ; Check for collisions. + if FileExist(filepath) { + loop + filepath := directory "\" filename " (" A_Index ")." extension + until !FileExist(filepath) + } + ; Fill a buffer with the available encoders. DllCall("gdiplus\GdipGetImageEncodersSize", "uint*", &count:=0, "uint*", &size:=0) ci := Buffer(size) From 0be142f13f7cc800c6d85de44e65c655a47cbfcc Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 25 Sep 2021 22:45:53 -0400 Subject: [PATCH 018/492] Only default timestamp filenames can be incremented --- ImagePut (for v1).ahk | 17 +++++++++-------- ImagePut.ahk | 17 +++++++++-------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 67cd785a..2048526a 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1497,16 +1497,17 @@ class ImagePut { extension := "png" } filename := RegExReplace(filename, "S)(?i:^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$|[<>:|?*\x00-\x1F\x22\/\\])") - if (filename == "") + if (filename == "") { FormatTime, filename,, % "yyyy-MM-dd HH?mm?ss" - filepath := directory "\" filename "." extension - - ; Check for collisions. - if FileExist(filepath) { - loop - filepath := directory "\" filename " (" A_Index ")." extension - until !FileExist(filepath) + filepath := directory "\" filename "." extension + if FileExist(filepath) { ; Check for collisions. + loop + filepath := directory "\" filename " (" A_Index ")." extension + until !FileExist(filepath) + } } + else + filepath := directory "\" filename "." extension ; Fill a buffer with the available encoders. DllCall("gdiplus\GdipGetImageEncodersSize", "uint*", count:=0, "uint*", size:=0) diff --git a/ImagePut.ahk b/ImagePut.ahk index 04c83deb..6951cdf9 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1497,16 +1497,17 @@ class ImagePut { extension := "png" } filename := RegExReplace(filename, "S)(?i:^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$|[<>:|?*\x00-\x1F\x22\/\\])") - if (filename == "") + if (filename == "") { filename := FormatTime(, "yyyy-MM-dd HH?mm?ss") - filepath := directory "\" filename "." extension - - ; Check for collisions. - if FileExist(filepath) { - loop - filepath := directory "\" filename " (" A_Index ")." extension - until !FileExist(filepath) + filepath := directory "\" filename "." extension + if FileExist(filepath) { ; Check for collisions. + loop + filepath := directory "\" filename " (" A_Index ")." extension + until !FileExist(filepath) + } } + else + filepath := directory "\" filename "." extension ; Fill a buffer with the available encoders. DllCall("gdiplus\GdipGetImageEncodersSize", "uint*", &count:=0, "uint*", &size:=0) From be10fbba8e9e9aaa3faf3184a781ab52412f5612 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 26 Sep 2021 11:23:32 -0400 Subject: [PATCH 019/492] spacing in wndclassex --- ImagePut (for v1).ahk | 26 +++++++++++++------------- ImagePut.ahk | 26 +++++++++++++------------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 2048526a..07cc419c 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1246,19 +1246,19 @@ class ImagePut { ; struct tagWNDCLASSEXA - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexa ; struct tagWNDCLASSEXW - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexw _ := (A_PtrSize = 4) - VarSetCapacity(wc, size := _ ? 48:80, 0) ; sizeof(WNDCLASSEX) = 48, 80 - NumPut( size, wc, 0, "uint") ; cbSize - NumPut( 0, wc, 4, "uint") ; style - NumPut( pWndProc, wc, 8, "ptr") ; lpfnWndProc - NumPut( 0, wc, _ ? 12:16, "int") ; cbClsExtra - NumPut( 0, wc, _ ? 16:20, "int") ; cbWndExtra - NumPut( 0, wc, _ ? 20:24, "ptr") ; hInstance - NumPut( 0, wc, _ ? 24:32, "ptr") ; hIcon - NumPut( hCursor, wc, _ ? 28:40, "ptr") ; hCursor - NumPut( hBrush, wc, _ ? 32:48, "ptr") ; hbrBackground - NumPut( 0, wc, _ ? 36:56, "ptr") ; lpszMenuName - NumPut( &cls, wc, _ ? 40:64, "ptr") ; lpszClassName - NumPut( 0, wc, _ ? 44:72, "ptr") ; hIconSm + VarSetCapacity(wc, size := _ ? 48:80, 0) ; sizeof(WNDCLASSEX) = 48, 80 + NumPut( size, wc, 0, "uint") ; cbSize + NumPut( 0, wc, 4, "uint") ; style + NumPut( pWndProc, wc, 8, "ptr") ; lpfnWndProc + NumPut( 0, wc, _ ? 12:16, "int") ; cbClsExtra + NumPut( 0, wc, _ ? 16:20, "int") ; cbWndExtra + NumPut( 0, wc, _ ? 20:24, "ptr") ; hInstance + NumPut( 0, wc, _ ? 24:32, "ptr") ; hIcon + NumPut( hCursor, wc, _ ? 28:40, "ptr") ; hCursor + NumPut( hBrush, wc, _ ? 32:48, "ptr") ; hbrBackground + NumPut( 0, wc, _ ? 36:56, "ptr") ; lpszMenuName + NumPut( &cls, wc, _ ? 40:64, "ptr") ; lpszClassName + NumPut( 0, wc, _ ? 44:72, "ptr") ; hIconSm ; Registers a window class for subsequent use in calls to the CreateWindow or CreateWindowEx function. DllCall("RegisterClassEx", "ptr", &wc, "ushort") diff --git a/ImagePut.ahk b/ImagePut.ahk index 6951cdf9..f7451acb 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1246,19 +1246,19 @@ class ImagePut { ; struct tagWNDCLASSEXA - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexa ; struct tagWNDCLASSEXW - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexw _ := (A_PtrSize = 4) - wc := Buffer(_ ? 48:80, 0) ; sizeof(WNDCLASSEX) = 48, 80 - NumPut( "uint", wc.size, wc, 0) ; cbSize - NumPut( "uint", 0, wc, 4) ; style - NumPut( "ptr", pWndProc, wc, 8) ; lpfnWndProc - NumPut( "int", 0, wc, _ ? 12:16) ; cbClsExtra - NumPut( "int", 0, wc, _ ? 16:20) ; cbWndExtra - NumPut( "ptr", 0, wc, _ ? 20:24) ; hInstance - NumPut( "ptr", 0, wc, _ ? 24:32) ; hIcon - NumPut( "ptr", hCursor, wc, _ ? 28:40) ; hCursor - NumPut( "ptr", hBrush, wc, _ ? 32:48) ; hbrBackground - NumPut( "ptr", 0, wc, _ ? 36:56) ; lpszMenuName - NumPut( "ptr", StrPtr(cls), wc, _ ? 40:64) ; lpszClassName - NumPut( "ptr", 0, wc, _ ? 44:72) ; hIconSm + wc := Buffer(_ ? 48:80, 0) ; sizeof(WNDCLASSEX) = 48, 80 + NumPut( "uint", wc.size, wc, 0) ; cbSize + NumPut( "uint", 0, wc, 4) ; style + NumPut( "ptr", pWndProc, wc, 8) ; lpfnWndProc + NumPut( "int", 0, wc, _ ? 12:16) ; cbClsExtra + NumPut( "int", 0, wc, _ ? 16:20) ; cbWndExtra + NumPut( "ptr", 0, wc, _ ? 20:24) ; hInstance + NumPut( "ptr", 0, wc, _ ? 24:32) ; hIcon + NumPut( "ptr", hCursor, wc, _ ? 28:40) ; hCursor + NumPut( "ptr", hBrush, wc, _ ? 32:48) ; hbrBackground + NumPut( "ptr", 0, wc, _ ? 36:56) ; lpszMenuName + NumPut( "ptr", StrPtr(cls), wc, _ ? 40:64) ; lpszClassName + NumPut( "ptr", 0, wc, _ ? 44:72) ; hIconSm ; Registers a window class for subsequent use in calls to the CreateWindow or CreateWindowEx function. DllCall("RegisterClassEx", "ptr", wc, "ushort") From 5c98d7bdc5d869d742192fff7fe80bb4c137773e Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 26 Sep 2021 12:58:11 -0400 Subject: [PATCH 020/492] Update is_URL --- ImagePut (for v1).ahk | 42 +++++++++++++++++++++++++++++++----------- ImagePut.ahk | 42 +++++++++++++++++++++++++++++++----------- 2 files changed, 62 insertions(+), 22 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 07cc419c..c99a0b6d 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -575,17 +575,37 @@ class ImagePut { } is_url(url) { - ; Thanks splattermania - https://www.php.net/manual/en/function.preg-match.php#93824 - - regex := "^(?i)" - . "((https?|ftp)\:\/\/)" ; SCHEME - . "([a-z0-9+!*(),;?&=\$_.-]+(\:[a-z0-9+!*(),;?&=\$_.-]+)?@)?" ; User and Pass - . "([a-z0-9-.]*)\.([a-z]{2,3})" ; Host or IP - . "(\:[0-9]{2,5})?" ; Port - . "(\/(?:[a-z0-9-_~!$&'()*+,;=:@]\.?)+)*\/?" ; Path - . "(\?[a-z+&\$_.-][a-z0-9;:@&%=+\/\$_.-]*)?" ; GET Query - . "(#[a-z_.-][a-z0-9+\$_.-]*)?$" ; Anchor - return (url ~= regex) + ; Thanks dperini - https://gist.github.com/dperini/729294 + ; Also see for comparisons: https://mathiasbynens.be/demo/url-regex + ; Modified to be compatible with AutoHotkey. \u0000 -> \x{0000}. + ; Force the declaration of the protocol because WinHttp requires it. + return url ~= "^(?i)" + . "(?:(?:https?|ftp):\/\/)" ; protocol identifier (FORCE) + . "(?:\S+(?::\S*)?@)?" ; user:pass BasicAuth (optional) + . "(?:" + ; IP address exclusion + ; private & local networks + . "(?!(?:10|127)(?:\.\d{1,3}){3})" + . "(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})" + . "(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})" + ; IP address dotted notation octets + ; excludes loopback network 0.0.0.0 + ; excludes reserved space >= 224.0.0.0 + ; excludes network & broadcast addresses + ; (first & last IP address of each class) + . "(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])" + . "(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}" + . "(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))" + . "|" + ; host & domain names, may end with dot + ; can be replaced by a shortest alternative + ; (?![-_])(?:[-\\w\\u00a1-\\uffff]{0,63}[^-_]\\.)+ + . "(?:(?:[a-z0-9\x{00a1}-\x{ffff}][a-z0-9\x{00a1}-\x{ffff}_-]{0,62})?[a-z0-9\x{00a1}-\x{ffff}]\.)+" + ; TLD identifier name, may end with dot + . "(?:[a-z\x{00a1}-\x{ffff}]{2,}\.?)" + . ")" + . "(?::\d{2,5})?" ; port number (optional) + . "(?:[/?#]\S*)?$" ; resource path (optional) } from_clipboard() { diff --git a/ImagePut.ahk b/ImagePut.ahk index f7451acb..766aa78a 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -575,17 +575,37 @@ class ImagePut { } static is_url(url) { - ; Thanks splattermania - https://www.php.net/manual/en/function.preg-match.php#93824 - - regex := "^(?i)" - . "((https?|ftp)\:\/\/)" ; SCHEME - . "([a-z0-9+!*(),;?&=\$_.-]+(\:[a-z0-9+!*(),;?&=\$_.-]+)?@)?" ; User and Pass - . "([a-z0-9-.]*)\.([a-z]{2,3})" ; Host or IP - . "(\:[0-9]{2,5})?" ; Port - . "(\/(?:[a-z0-9-_~!$&'()*+,;=:@]\.?)+)*\/?" ; Path - . "(\?[a-z+&\$_.-][a-z0-9;:@&%=+\/\$_.-]*)?" ; GET Query - . "(#[a-z_.-][a-z0-9+\$_.-]*)?$" ; Anchor - return (url ~= regex) + ; Thanks dperini - https://gist.github.com/dperini/729294 + ; Also see for comparisons: https://mathiasbynens.be/demo/url-regex + ; Modified to be compatible with AutoHotkey. \u0000 -> \x{0000}. + ; Force the declaration of the protocol because WinHttp requires it. + return url ~= "^(?i)" + . "(?:(?:https?|ftp):\/\/)" ; protocol identifier (FORCE) + . "(?:\S+(?::\S*)?@)?" ; user:pass BasicAuth (optional) + . "(?:" + ; IP address exclusion + ; private & local networks + . "(?!(?:10|127)(?:\.\d{1,3}){3})" + . "(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})" + . "(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})" + ; IP address dotted notation octets + ; excludes loopback network 0.0.0.0 + ; excludes reserved space >= 224.0.0.0 + ; excludes network & broadcast addresses + ; (first & last IP address of each class) + . "(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])" + . "(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}" + . "(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))" + . "|" + ; host & domain names, may end with dot + ; can be replaced by a shortest alternative + ; (?![-_])(?:[-\\w\\u00a1-\\uffff]{0,63}[^-_]\\.)+ + . "(?:(?:[a-z0-9\x{00a1}-\x{ffff}][a-z0-9\x{00a1}-\x{ffff}_-]{0,62})?[a-z0-9\x{00a1}-\x{ffff}]\.)+" + ; TLD identifier name, may end with dot + . "(?:[a-z\x{00a1}-\x{ffff}]{2,}\.?)" + . ")" + . "(?::\d{2,5})?" ; port number (optional) + . "(?:[/?#]\S*)?$" ; resource path (optional) } static from_clipboard() { From 877340361c38e3d601485e5e1edbe40a5a72b6c5 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 26 Sep 2021 16:21:12 -0400 Subject: [PATCH 021/492] ByRefs removed from v1 --- ImagePut (for v1).ahk | 66 +++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index c99a0b6d..df678f61 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -10,96 +10,96 @@ ; Puts the image into a file format and returns a base64 encoded string. ; extension - File Encoding | string -> bmp, gif, jpg, png, tiff ; quality - JPEG Quality Level | integer -> 0 - 100 -ImagePutBase64(ByRef image, extension := "", quality := "") { +ImagePutBase64(image, extension := "", quality := "") { return ImagePut("base64", image,,, extension, quality) } ; Puts the image into a GDI+ Bitmap and returns a pointer. -ImagePutBitmap(ByRef image) { +ImagePutBitmap(image) { return ImagePut("bitmap", image) } ; Puts the image into a GDI+ Bitmap and returns a buffer object with GDI+ scope. -ImagePutBuffer(ByRef image) { +ImagePutBuffer(image) { return ImagePut("buffer", image) } ; Puts the image onto the clipboard and returns an empty string. -ImagePutClipboard(ByRef image) { +ImagePutClipboard(image) { return ImagePut("clipboard", image) } ; Puts the image as the cursor and returns the variable A_Cursor. ; xHotspot - X Click Point | pixel -> 0 - width ; yHotspot - Y Click Point | pixel -> 0 - height -ImagePutCursor(ByRef image, xHotspot := "", yHotspot := "") { +ImagePutCursor(image, xHotspot := "", yHotspot := "") { return ImagePut("cursor", image,,, xHotspot, yHotspot) } ; Puts the image behind the desktop icons and returns the string "desktop". ; scale - Scale Factor | real -> A_ScreenHeight / height. -ImagePutDesktop(ByRef image, scale := 1) { +ImagePutDesktop(image, scale := 1) { return ImagePut("desktop", image,, scale) } ; Puts the image into a file and returns a relative filepath. ; filepath - Filepath + Extension | string -> *.bmp, *.gif, *.jpg, *.png, *.tiff ; quality - JPEG Quality Level | integer -> 0 - 100 -ImagePutFile(ByRef image, filepath := "", quality := "") { +ImagePutFile(image, filepath := "", quality := "") { return ImagePut("file", image,,, filepath, quality) } ; Puts the image into a device independent bitmap and returns the handle. ; alpha - Alpha Replacement Color | RGB -> 0xFFFFFF -ImagePutHBitmap(ByRef image, alpha := "") { +ImagePutHBitmap(image, alpha := "") { return ImagePut("hBitmap", image,,, alpha) } ; Puts the image into a file format and returns a hexadecimal encoded string. ; extension - File Encoding | string -> bmp, gif, jpg, png, tiff ; quality - JPEG Quality Level | integer -> 0 - 100 -ImagePutHex(ByRef image, extension := "", quality := "") { +ImagePutHex(image, extension := "", quality := "") { return ImagePut("hex", image,,, extension, quality) } ; Puts the image into an icon and returns the handle. -ImagePutHIcon(ByRef image) { +ImagePutHIcon(image) { return ImagePut("hBitmap", image) } ; Puts the image into a file format and returns a pointer to a RandomAccessStream. ; extension - File Encoding | string -> bmp, gif, jpg, png, tiff ; quality - JPEG Quality Level | integer -> 0 - 100 -ImagePutRandomAccessStream(ByRef image, extension := "", quality := "") { +ImagePutRandomAccessStream(image, extension := "", quality := "") { return ImagePut("RandomAccessStream", image,,, extension, quality) } ; Puts the image on the shared screen device context and returns an array of coordinates. ; screenshot - Screen Coordinates | array -> [x,y,w,h] or [0,0] ; alpha - Alpha Replacement Color | RGB -> 0xFFFFFF -ImagePutScreenshot(ByRef image, screenshot := "", alpha := "") { +ImagePutScreenshot(image, screenshot := "", alpha := "") { return ImagePut("screenshot", image,,, screenshot, alpha) } ; Puts the image into a file format and returns a pointer to a stream. ; extension - File Encoding | string -> bmp, gif, jpg, png, tiff ; quality - JPEG Quality Level | integer -> 0 - 100 -ImagePutStream(ByRef image, extension := "", quality := "") { +ImagePutStream(image, extension := "", quality := "") { return ImagePut("stream", image,,, extension, quality) } ; Puts the image as the desktop wallpaper and returns the string "wallpaper". -ImagePutWallpaper(ByRef image) { +ImagePutWallpaper(image) { return ImagePut("wallpaper", image) } ; Puts the image in a window and returns a handle to a window. ; title - Window Caption Title | string -> MyTitle -ImagePutWindow(ByRef image, title := "") { +ImagePutWindow(image, title := "") { return ImagePut("window", image,,, title) } -ImagePut(cotype, ByRef image, crop := "", scale := "", terms*) { +ImagePut(cotype, image, crop := "", scale := "", terms*) { return ImagePut.call(cotype, image, crop, scale, terms*) } @@ -112,7 +112,7 @@ class ImagePut { ; crop - Crop Coordinates | array -> [x,y,w,h] could be negative or percent. ; scale - Scale Factor | real -> 2.0 ; terms* - Additional Parameters | variadic -> Extra parameters found in toCotype(). - call(cotype, ByRef image, crop := "", scale := "", terms*) { + call(cotype, image, crop := "", scale := "", terms*) { this.gdiplusStartup() @@ -156,7 +156,7 @@ class ImagePut { return coimage } - DontVerifyImageType(ByRef image) { + DontVerifyImageType(image) { if !IsObject(image) throw Exception("Must be an object.") @@ -262,7 +262,7 @@ class ImagePut { throw Exception("Invalid type.") } - ImageType(ByRef image) { + ImageType(image) { if (image == "") { DllCall("OpenClipboard", "ptr", 0) result := !DllCall("IsClipboardFormatAvailable", "uint", DllCall("RegisterClipboardFormat", "str", "png", "uint")) && !DllCall("IsClipboardFormatAvailable", "uint", 2) @@ -356,7 +356,7 @@ class ImagePut { throw Exception("Image type could not be identified.") } - toBitmap(type, ByRef image) { + toBitmap(type, image) { if (type = "clipboard") return this.from_clipboard() @@ -638,7 +638,7 @@ class ImagePut { return pBitmap } - from_screenshot(ByRef image) { + from_screenshot(image) { ; Thanks tic - https://www.autohotkey.com/boards/viewtopic.php?t=6517 ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader @@ -674,7 +674,7 @@ class ImagePut { return pBitmap } - from_window(ByRef image) { + from_window(image) { ; Thanks tic - https://www.autohotkey.com/boards/viewtopic.php?t=6517 ; Get the handle to the window. @@ -820,7 +820,7 @@ class ImagePut { return pBitmap } - from_url(ByRef image) { + from_url(image) { req := ComObjCreate("WinHttp.WinHttpRequest.5.1") req.Open("GET", image) req.Send() @@ -830,12 +830,12 @@ class ImagePut { return pBitmap } - from_file(ByRef image) { + from_file(image) { DllCall("gdiplus\GdipCreateBitmapFromFile", "wstr", image, "ptr*", pBitmap:=0) return pBitmap } - from_monitor(ByRef image) { + from_monitor(image) { if (image > 0) { SysGet _, Monitor, image x := _Left @@ -851,7 +851,7 @@ class ImagePut { return this.from_screenshot([x,y,w,h]) } - from_hBitmap(ByRef image) { + from_hBitmap(image) { ; struct DIBSECTION - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-dibsection ; struct BITMAP - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmap VarSetCapacity(dib, size := 64+5*A_PtrSize) ; sizeof(DIBSECTION) = 84, 104 @@ -922,7 +922,7 @@ class ImagePut { return pBitmap } - from_hIcon(ByRef image) { + from_hIcon(image) { ; struct ICONINFO - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-iconinfo VarSetCapacity(ii, 8+3*A_PtrSize, 0) ; sizeof(ICONINFO) = 20, 32 DllCall("GetIconInfo", "ptr", image, "ptr", &ii) @@ -989,17 +989,17 @@ class ImagePut { return pBitmap } - from_bitmap(ByRef image) { + from_bitmap(image) { DllCall("gdiplus\GdipCloneImage", "ptr", image, "ptr*", pBitmap:=0) return pBitmap } - from_stream(ByRef image) { + from_stream(image) { DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", image, "ptr*", pBitmap:=0) return pBitmap } - from_RandomAccessStream(ByRef image) { + from_RandomAccessStream(image) { ; Get the Class ID from a GUID string. VarSetCapacity(CLSID, 16, 0) if result := DllCall("ole32\CLSIDFromString", "wstr", "{0000000C-0000-0000-C000-000000000046}", "ptr", &CLSID, "uint") @@ -1017,7 +1017,7 @@ class ImagePut { return pBitmap } - from_hex(ByRef image) { + from_hex(image) { ; Trim whitespace and remove header. image := Trim(image) image := RegExReplace(image, "^(0[xX])") @@ -1037,7 +1037,7 @@ class ImagePut { return pBitmap } - from_base64(ByRef image) { + from_base64(image) { ; Trim whitespace and remove header. image := Trim(image) image := RegExReplace(image, "^data:image\/[a-z]+;base64,") @@ -1057,7 +1057,7 @@ class ImagePut { return pBitmap } - from_sprite(ByRef image) { + from_sprite(image) { ; Create a source pBitmap and extract the width and height. if DllCall("gdiplus\GdipCreateBitmapFromFile", "wstr", image, "ptr*", sBitmap:=0) if !(sBitmap := this.from_url(image)) From 6b36c5671d635d44b7f274c88b8b392bc648ae36 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 26 Sep 2021 17:54:17 -0400 Subject: [PATCH 022/492] Streamline object and buffer types --- ImagePut (for v1).ahk | 14 +++++++------- ImagePut.ahk | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index df678f61..adc418a1 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -272,12 +272,12 @@ class ImagePut { throw Exception("Image data is an empty string.") } if IsObject(image) { - ; An "object" is an object that implements a Bitmap() method returning a pointer to a GDI+ bitmap. - if IsFunc(image.Bitmap) + ; A "object" has a pBitmap property that points to an internal GDI+ bitmap. + if image.HasKey("pBitmap") return "object" - ; A "buffer" is an AutoHotkey v2 buffer object. - if image.HasKey("pBitmap") + ; A "buffer" is an object with ptr and size properties. + if image.HasKey("ptr") && image.HasKey("size") return "buffer" ; A "screenshot" is an array of 4 numbers. @@ -361,11 +361,11 @@ class ImagePut { if (type = "clipboard") return this.from_clipboard() - if (type = "object") ; Special - return image.Bitmap() + if (type = "object") + return this.from_object(image) if (type = "buffer") - return this.from_bitmap(image.pBitmap) + return this.from_buffer(image) if (type = "screenshot") return this.from_screenshot(image) diff --git a/ImagePut.ahk b/ImagePut.ahk index 766aa78a..ca0c2e42 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -272,12 +272,12 @@ class ImagePut { if (image.base.HasOwnProp("__class") && image.base.__class == "ClipboardAll") return "clipboard" - ; An "object" is an object that implements a Bitmap() method returning a pointer to a GDI+ bitmap. - if image.HasMethod("Bitmap") + ; A "object" has a pBitmap property that points to an internal GDI+ bitmap. + if image.HasOwnProp("pBitmap") return "object" - ; A "buffer" is an AutoHotkey v2 buffer object. - if image.HasOwnProp("pBitmap") + ; A "buffer" is an object with ptr and size properties. + if image.HasOwnProp("ptr") && image.HasOwnProp("size") return "buffer" ; A "screenshot" is an array of 4 numbers. @@ -361,11 +361,11 @@ class ImagePut { if (type = "clipboard") return this.from_clipboard() - if (type = "object") ; Special - return image.Bitmap() + if (type = "object") + return this.from_object(image) if (type = "buffer") - return this.from_bitmap(image.pBitmap) + return this.from_buffer(image) if (type = "screenshot") return this.from_screenshot(image) From 5f3b7a1a9db2d39bf16f9800f8e471dca47c0b2a Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 26 Sep 2021 18:04:20 -0400 Subject: [PATCH 023/492] Implement from_object --- ImagePut (for v1).ahk | 8 ++++++++ ImagePut.ahk | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index adc418a1..3398c2f4 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -638,6 +638,14 @@ class ImagePut { return pBitmap } + from_object(image) { + return this.from_bitmap(image.pBitmap) + } + + from_buffer(image) { + ; to do + } + from_screenshot(image) { ; Thanks tic - https://www.autohotkey.com/boards/viewtopic.php?t=6517 diff --git a/ImagePut.ahk b/ImagePut.ahk index ca0c2e42..65444254 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -638,6 +638,14 @@ class ImagePut { return pBitmap } + static from_object(image) { + return this.from_bitmap(image.pBitmap) + } + + static from_buffer(image) { + ; to do + } + static from_screenshot(image) { ; Thanks tic - https://www.autohotkey.com/boards/viewtopic.php?t=6517 From 6101ab03cd8f4922a070fa3cdee400b2628a1071 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 26 Sep 2021 18:39:45 -0400 Subject: [PATCH 024/492] Comment about DIB not supporting transparency --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 3398c2f4..12373902 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -627,7 +627,7 @@ class ImagePut { ObjRelease(pStream) } - ; Fallback to CF_BITMAP. + ; Fallback to CF_BITMAP. This format does not support transparency even with put_hBitmap(). else if DllCall("IsClipboardFormatAvailable", "uint", 2, "int") { hBitmap := DllCall("GetClipboardData", "uint", 2, "ptr") DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "ptr", hBitmap, "ptr", 0, "ptr*", pBitmap:=0) diff --git a/ImagePut.ahk b/ImagePut.ahk index 65444254..7c909b8e 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -627,7 +627,7 @@ class ImagePut { ObjRelease(pStream) } - ; Fallback to CF_BITMAP. + ; Fallback to CF_BITMAP. This format does not support transparency even with put_hBitmap(). else if DllCall("IsClipboardFormatAvailable", "uint", 2, "int") { hBitmap := DllCall("GetClipboardData", "uint", 2, "ptr") DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "ptr", hBitmap, "ptr", 0, "ptr*", &pBitmap:=0) From 03ea2b434970b39ed8724e8019a659255cf895b6 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 26 Sep 2021 18:46:25 -0400 Subject: [PATCH 025/492] IStream properly freed on v2 --- ImagePut.ahk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index 7c909b8e..96e5defd 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -834,7 +834,7 @@ class ImagePut { req.Send() IStream := ComObjQuery(req.ResponseStream, "{0000000C-0000-0000-C000-000000000046}") DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", IStream, "ptr*", &pBitmap:=0) - ObjRelease(IStream.ptr) + IStream := "" return pBitmap } From 5c15a905e09270d4c618662f867df16a85570e3e Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 26 Sep 2021 18:50:28 -0400 Subject: [PATCH 026/492] comments in from_hIcon() --- ImagePut (for v1).ahk | 8 ++++---- ImagePut.ahk | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 12373902..6f085ab0 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -932,15 +932,15 @@ class ImagePut { from_hIcon(image) { ; struct ICONINFO - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-iconinfo - VarSetCapacity(ii, 8+3*A_PtrSize, 0) ; sizeof(ICONINFO) = 20, 32 + VarSetCapacity(ii, 8+3*A_PtrSize, 0) ; sizeof(ICONINFO) = 20, 32 DllCall("GetIconInfo", "ptr", image, "ptr", &ii) ; xHotspot := NumGet(ii, 4, "uint") ; yHotspot := NumGet(ii, 8, "uint") - , hbmMask := NumGet(ii, 8+A_PtrSize, "ptr") ; x86:12, x64:16 - , hbmColor := NumGet(ii, 8+2*A_PtrSize, "ptr") ; x86:16, x64:24 + , hbmMask := NumGet(ii, 8+A_PtrSize, "ptr") ; 12, 16 + , hbmColor := NumGet(ii, 8+2*A_PtrSize, "ptr") ; 16, 24 ; struct BITMAP - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmap - VarSetCapacity(bm, size := 16+2*A_PtrSize) ; sizeof(BITMAP) = 24, 32 + VarSetCapacity(bm, size := 16+2*A_PtrSize) ; sizeof(BITMAP) = 24, 32 DllCall("GetObject", "ptr", hbmMask, "int", size, "ptr", &bm) , width := NumGet(bm, 4, "uint") , height := NumGet(bm, 8, "uint") / (hbmColor ? 1 : 2) ; Black and White cursors have doubled height. diff --git a/ImagePut.ahk b/ImagePut.ahk index 96e5defd..f94cec9f 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -940,7 +940,7 @@ class ImagePut { , hbmColor := NumGet(ii, 8+2*A_PtrSize, "ptr") ; 16, 24 ; struct BITMAP - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmap - bm := Buffer(16+2*A_PtrSize) ; sizeof(BITMAP) = 24, 32 + bm := Buffer(16+2*A_PtrSize) ; sizeof(BITMAP) = 24, 32 DllCall("GetObject", "ptr", hbmMask, "int", bm.size, "ptr", bm) , width := NumGet(bm, 4, "uint") , height := NumGet(bm, 8, "uint") / (hbmColor ? 1 : 2) ; Black and White cursors have doubled height. From d840f4826386e4334dbade7d33cf291db6b4f909 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 26 Sep 2021 18:55:52 -0400 Subject: [PATCH 027/492] spacing in CryptStringToBinary --- ImagePut (for v1).ahk | 8 ++++---- ImagePut.ahk | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 6f085ab0..65387728 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1032,10 +1032,10 @@ class ImagePut { ; Converts the image to binary data by first asking for the size. DllCall("crypt32\CryptStringToBinary" - , "ptr", &image, "uint", 0, "uint", 0x0000000C, "ptr", 0, "uint*", size:=0, "ptr", 0, "ptr", 0) + , "ptr", &image, "uint", 0, "uint", 0xC, "ptr", 0, "uint*", size:=0, "ptr", 0, "ptr", 0) VarSetCapacity(bin, size, 0) DllCall("crypt32\CryptStringToBinary" - , "ptr", &image, "uint", 0, "uint", 0x0000000C, "ptr", &bin, "uint*", size , "ptr", 0, "ptr", 0) + , "ptr", &image, "uint", 0, "uint", 0xC, "ptr", &bin, "uint*", size, "ptr", 0, "ptr", 0) ; Makes a stream for conversion into a pBitmap. pStream := DllCall("shlwapi\SHCreateMemStream", "ptr", &bin, "uint", size, "ptr") @@ -1052,10 +1052,10 @@ class ImagePut { ; Converts the image to binary data by first asking for the size. DllCall("crypt32\CryptStringToBinary" - , "ptr", &image, "uint", 0, "uint", 0x00000001, "ptr", 0, "uint*", size:=0, "ptr", 0, "ptr", 0) + , "ptr", &image, "uint", 0, "uint", 0x1, "ptr", 0, "uint*", size:=0, "ptr", 0, "ptr", 0) VarSetCapacity(bin, size, 0) DllCall("crypt32\CryptStringToBinary" - , "ptr", &image, "uint", 0, "uint", 0x00000001, "ptr", &bin, "uint*", size , "ptr", 0, "ptr", 0) + , "ptr", &image, "uint", 0, "uint", 0x1, "ptr", &bin, "uint*", size, "ptr", 0, "ptr", 0) ; Makes a stream for conversion into a pBitmap. pStream := DllCall("shlwapi\SHCreateMemStream", "ptr", &bin, "uint", size, "ptr") diff --git a/ImagePut.ahk b/ImagePut.ahk index f94cec9f..56c127e4 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1032,10 +1032,10 @@ class ImagePut { ; Converts the image to binary data by first asking for the size. DllCall("crypt32\CryptStringToBinary" - , "ptr", StrPtr(image), "uint", 0, "uint", 0x0000000C, "ptr", 0, "uint*", &size:=0, "ptr", 0, "ptr", 0) + , "ptr", StrPtr(image), "uint", 0, "uint", 0xC, "ptr", 0, "uint*", &size:=0, "ptr", 0, "ptr", 0) bin := Buffer(size, 0) DllCall("crypt32\CryptStringToBinary" - , "ptr", StrPtr(image), "uint", 0, "uint", 0x0000000C, "ptr", bin, "uint*", size , "ptr", 0, "ptr", 0) + , "ptr", StrPtr(image), "uint", 0, "uint", 0xC, "ptr", bin, "uint*", size, "ptr", 0, "ptr", 0) ; Makes a stream for conversion into a pBitmap. pStream := DllCall("shlwapi\SHCreateMemStream", "ptr", bin, "uint", size, "ptr") @@ -1052,10 +1052,10 @@ class ImagePut { ; Converts the image to binary data by first asking for the size. DllCall("crypt32\CryptStringToBinary" - , "ptr", StrPtr(image), "uint", 0, "uint", 0x00000001, "ptr", 0, "uint*", &size:=0, "ptr", 0, "ptr", 0) + , "ptr", StrPtr(image), "uint", 0, "uint", 0x1, "ptr", 0, "uint*", &size:=0, "ptr", 0, "ptr", 0) bin := Buffer(size, 0) DllCall("crypt32\CryptStringToBinary" - , "ptr", StrPtr(image), "uint", 0, "uint", 0x00000001, "ptr", bin, "uint*", size , "ptr", 0, "ptr", 0) + , "ptr", StrPtr(image), "uint", 0, "uint", 0x1, "ptr", bin, "uint*", size, "ptr", 0, "ptr", 0) ; Makes a stream for conversion into a pBitmap. pStream := DllCall("shlwapi\SHCreateMemStream", "ptr", bin, "uint", size, "ptr") From 18313f76fa6d570703f191b1972a37c765f43508 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 26 Sep 2021 19:05:53 -0400 Subject: [PATCH 028/492] v2-beta.1 Fix DllCall function binding --- ImagePut.ahk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index 56c127e4..6dd606d8 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1463,7 +1463,7 @@ class ImagePut { DllCall("SystemParametersInfo", "uint", 20, "uint", 0, "str", buf, "uint", 2) ; This is a delayed delete call. #Persistent may be required on v1. - DeleteFile := Func("DllCall").Bind("DeleteFile", "str", filepath) + DeleteFile := DllCall.Bind("DeleteFile", "str", filepath) SetTimer DeleteFile, -2000 return "wallpaper" From 61347edb47065b74f4136d5fa1a009af21a487f1 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 26 Sep 2021 19:42:20 -0400 Subject: [PATCH 029/492] pCodec code moved to its own function --- ImagePut (for v1).ahk | 109 ++++++++++++++++-------------------------- ImagePut.ahk | 109 ++++++++++++++++-------------------------- 2 files changed, 82 insertions(+), 136 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 65387728..228c2b16 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1537,40 +1537,8 @@ class ImagePut { else filepath := directory "\" filename "." extension - ; Fill a buffer with the available encoders. - DllCall("gdiplus\GdipGetImageEncodersSize", "uint*", count:=0, "uint*", size:=0) - VarSetCapacity(ci, size) - DllCall("gdiplus\GdipGetImageEncoders", "uint", count, "uint", size, "ptr", &ci) - if !(count && size) - throw Exception("Could not get a list of image codec encoders on this system.") - - ; Search for an encoder with a matching extension. - Loop % count - EncoderExtensions := StrGet(NumGet(ci, (idx:=(48+7*A_PtrSize)*(A_Index-1))+32+3*A_PtrSize, "uptr"), "UTF-16") - until InStr(EncoderExtensions, "*." extension) - - ; Get the pointer to the index/offset of the matching encoder. - if !(pCodec := &ci + idx) - throw Exception("Could not find a matching encoder for the specified file format.") - - ; JPEG is a lossy image format that requires a quality value from 0-100. Default quality is 75. - if (extension ~= "^(?i:jpg|jpeg|jpe|jfif)$" - && 0 <= quality && quality <= 100 && quality != 75) { - DllCall("gdiplus\GdipGetEncoderParameterListSize", "ptr", pBitmap, "ptr", pCodec, "uint*", size:=0) - VarSetCapacity(EncoderParameters, size, 0) - DllCall("gdiplus\GdipGetEncoderParameterList", "ptr", pBitmap, "ptr", pCodec, "uint", size, "ptr", &EncoderParameters) - - ; Search for an encoder parameter with 1 value of type 6. - Loop % NumGet(EncoderParameters, "uint") - elem := (24+A_PtrSize)*(A_Index-1) + A_PtrSize - until (NumGet(EncoderParameters, elem+16, "uint") = 1) && (NumGet(EncoderParameters, elem+20, "uint") = 6) - - ; struct EncoderParameter - http://www.jose.it-berater.org/gdiplus/reference/structures/encoderparameter.htm - ep := &EncoderParameters + elem - A_PtrSize ; sizeof(EncoderParameter) = 28, 32 - NumPut( 1, ep+0, 0, "uptr") ; Must be 1. - NumPut( 4, ep+0, 20+A_PtrSize, "uint") ; Type - NumPut(quality, NumGet(ep+24+A_PtrSize, "uptr"), "uint") ; Value (pointer) - } + ; Select the proper codec based on the extension of the file. + this.select_codec(pBitmap, extension, quality, pCodec, ep) ; Write the file to disk using the specified encoder and encoding parameters with exponential backoff. loop @@ -1639,40 +1607,8 @@ class ImagePut { if !(extension ~= "^(?i:bmp|dib|rle|jpg|jpeg|jpe|jfif|gif|tif|tiff|png)$") extension := "tif" - ; Fill a buffer with the available encoders. - DllCall("gdiplus\GdipGetImageEncodersSize", "uint*", count:=0, "uint*", size:=0) - VarSetCapacity(ci, size) - DllCall("gdiplus\GdipGetImageEncoders", "uint", count, "uint", size, "ptr", &ci) - if !(count && size) - throw Exception("Could not get a list of image codec encoders on this system.") - - ; Search for an encoder with a matching extension. - Loop % count - EncoderExtensions := StrGet(NumGet(ci, (idx:=(48+7*A_PtrSize)*(A_Index-1))+32+3*A_PtrSize, "uptr"), "UTF-16") - until InStr(EncoderExtensions, "*." extension) - - ; Get the pointer to the index/offset of the matching encoder. - if !(pCodec := &ci + idx) - throw Exception("Could not find a matching encoder for the specified file format.") - - ; JPEG is a lossy image format that requires a quality value from 0-100. Default quality is 75. - if (extension ~= "^(?i:jpg|jpeg|jpe|jfif)$" - && 0 <= quality && quality <= 100 && quality != 75) { - DllCall("gdiplus\GdipGetEncoderParameterListSize", "ptr", pBitmap, "ptr", pCodec, "uint*", size:=0) - VarSetCapacity(EncoderParameters, size, 0) - DllCall("gdiplus\GdipGetEncoderParameterList", "ptr", pBitmap, "ptr", pCodec, "uint", size, "ptr", &EncoderParameters) - - ; Search for an encoder parameter with 1 value of type 6. - Loop % NumGet(EncoderParameters, "uint") - elem := (24+A_PtrSize)*(A_Index-1) + A_PtrSize - until (NumGet(EncoderParameters, elem+16, "uint") = 1) && (NumGet(EncoderParameters, elem+20, "uint") = 6) - - ; struct EncoderParameter - http://www.jose.it-berater.org/gdiplus/reference/structures/encoderparameter.htm - ep := &EncoderParameters + elem - A_PtrSize ; sizeof(EncoderParameter) = 28, 32 - NumPut( 1, ep+0, 0, "uptr") ; Must be 1. - NumPut( 4, ep+0, 20+A_PtrSize, "uint") ; Type - NumPut(quality, NumGet(ep+24+A_PtrSize, "uptr"), "uint") ; Value (pointer) - } + ; Select the proper codec based on the extension of the file. + this.select_codec(pBitmap, extension, quality, pCodec, ep) ; Create a Stream. DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "int", true, "ptr*", pStream:=0) @@ -1747,6 +1683,43 @@ class ImagePut { return StrGet(&base64, length, "CP0") } + select_codec(pBitmap, extension, quality, ByRef pCodec, ByRef ep) { + ; Fill a buffer with the available encoders. + DllCall("gdiplus\GdipGetImageEncodersSize", "uint*", count:=0, "uint*", size:=0) + VarSetCapacity(ci, size) + DllCall("gdiplus\GdipGetImageEncoders", "uint", count, "uint", size, "ptr", &ci) + if !(count && size) + throw Exception("Could not get a list of image codec encoders on this system.") + + ; Search for an encoder with a matching extension. + loop % count + EncoderExtensions := StrGet(NumGet(ci, (idx:=(48+7*A_PtrSize)*(A_Index-1))+32+3*A_PtrSize, "uptr"), "UTF-16") + until InStr(EncoderExtensions, "*." extension) + + ; Get the pointer to the index/offset of the matching encoder. + if !(pCodec := &ci + idx) + throw Exception("Could not find a matching encoder for the specified file format.") + + ; JPEG is a lossy image format that requires a quality value from 0-100. Default quality is 75. + if (extension ~= "^(?i:jpg|jpeg|jpe|jfif)$" + && quality ~= "^\d+$" && 0 <= quality && quality <= 100 && quality != 75) { + DllCall("gdiplus\GdipGetEncoderParameterListSize", "ptr", pBitmap, "ptr", pCodec, "uint*", size:=0) + VarSetCapacity(EncoderParameters, size, 0) + DllCall("gdiplus\GdipGetEncoderParameterList", "ptr", pBitmap, "ptr", pCodec, "uint", size, "ptr", &EncoderParameters) + + ; Search for an encoder parameter with 1 value of type 6. + loop % NumGet(EncoderParameters, "uint") + elem := (24+A_PtrSize)*(A_Index-1) + A_PtrSize + until (NumGet(EncoderParameters, elem+16, "uint") = 1) && (NumGet(EncoderParameters, elem+20, "uint") = 6) + + ; struct EncoderParameter - http://www.jose.it-berater.org/gdiplus/reference/structures/encoderparameter.htm + ep := &EncoderParameters + elem - A_PtrSize ; sizeof(EncoderParameter) = 28, 32 + NumPut( 1, ep+0, 0, "uptr") ; Must be 1. + NumPut( 4, ep+0, 20+A_PtrSize, "uint") ; Type + NumPut(quality, NumGet(ep+24+A_PtrSize, "uptr"), "uint") ; Value (Set a pointer) + } + } + ; All references to gdiplus and pToken must be absolute! static gdiplus := 0, pToken := 0 diff --git a/ImagePut.ahk b/ImagePut.ahk index 6dd606d8..a4d88143 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1537,40 +1537,8 @@ class ImagePut { else filepath := directory "\" filename "." extension - ; Fill a buffer with the available encoders. - DllCall("gdiplus\GdipGetImageEncodersSize", "uint*", &count:=0, "uint*", &size:=0) - ci := Buffer(size) - DllCall("gdiplus\GdipGetImageEncoders", "uint", count, "uint", size, "ptr", ci) - if !(count && size) - throw Error("Could not get a list of image codec encoders on this system.") - - ; Search for an encoder with a matching extension. - Loop count - EncoderExtensions := StrGet(NumGet(ci, (idx:=(48+7*A_PtrSize)*(A_Index-1))+32+3*A_PtrSize, "uptr"), "UTF-16") - until InStr(EncoderExtensions, "*." extension) - - ; Get the pointer to the index/offset of the matching encoder. - if !(pCodec := ci.ptr + idx) - throw Error("Could not find a matching encoder for the specified file format.") - - ; JPEG is a lossy image format that requires a quality value from 0-100. Default quality is 75. - if (extension ~= "^(?i:jpg|jpeg|jpe|jfif)$" - && IsInteger(quality) && 0 <= quality && quality <= 100 && quality != 75) { - DllCall("gdiplus\GdipGetEncoderParameterListSize", "ptr", pBitmap, "ptr", pCodec, "uint*", &size:=0) - EncoderParameters := Buffer(size, 0) - DllCall("gdiplus\GdipGetEncoderParameterList", "ptr", pBitmap, "ptr", pCodec, "uint", size, "ptr", EncoderParameters) - - ; Search for an encoder parameter with 1 value of type 6. - Loop NumGet(EncoderParameters, "uint") - elem := (24+A_PtrSize)*(A_Index-1) + A_PtrSize - until (NumGet(EncoderParameters, elem+16, "uint") = 1) && (NumGet(EncoderParameters, elem+20, "uint") = 6) - - ; struct EncoderParameter - http://www.jose.it-berater.org/gdiplus/reference/structures/encoderparameter.htm - ep := EncoderParameters.ptr + elem - A_PtrSize ; sizeof(EncoderParameter) = 28, 32 - NumPut( "uptr", 1, ep) ; Must be 1. - NumPut( "uint", 4, ep, 20+A_PtrSize) ; Type - NumPut( "uint", quality, NumGet(ep+24+A_PtrSize, "uptr")) ; Value (pointer) - } + ; Select the proper codec based on the extension of the file. + this.select_codec(pBitmap, extension, quality, &pCodec, &ep) ; Write the file to disk using the specified encoder and encoding parameters with exponential backoff. loop @@ -1639,40 +1607,8 @@ class ImagePut { if !(extension ~= "^(?i:bmp|dib|rle|jpg|jpeg|jpe|jfif|gif|tif|tiff|png)$") extension := "tif" - ; Fill a buffer with the available encoders. - DllCall("gdiplus\GdipGetImageEncodersSize", "uint*", &count:=0, "uint*", &size:=0) - ci := Buffer(size) - DllCall("gdiplus\GdipGetImageEncoders", "uint", count, "uint", size, "ptr", ci) - if !(count && size) - throw Error("Could not get a list of image codec encoders on this system.") - - ; Search for an encoder with a matching extension. - Loop count - EncoderExtensions := StrGet(NumGet(ci, (idx:=(48+7*A_PtrSize)*(A_Index-1))+32+3*A_PtrSize, "uptr"), "UTF-16") - until InStr(EncoderExtensions, "*." extension) - - ; Get the pointer to the index/offset of the matching encoder. - if !(pCodec := ci.ptr + idx) - throw Error("Could not find a matching encoder for the specified file format.") - - ; JPEG is a lossy image format that requires a quality value from 0-100. Default quality is 75. - if (extension ~= "^(?i:jpg|jpeg|jpe|jfif)$" - && IsInteger(quality) && 0 <= quality && quality <= 100 && quality != 75) { - DllCall("gdiplus\GdipGetEncoderParameterListSize", "ptr", pBitmap, "ptr", pCodec, "uint*", &size:=0) - EncoderParameters := Buffer(size, 0) - DllCall("gdiplus\GdipGetEncoderParameterList", "ptr", pBitmap, "ptr", pCodec, "uint", size, "ptr", EncoderParameters) - - ; Search for an encoder parameter with 1 value of type 6. - Loop NumGet(EncoderParameters, "uint") - elem := (24+A_PtrSize)*(A_Index-1) + A_PtrSize - until (NumGet(EncoderParameters, elem+16, "uint") = 1) && (NumGet(EncoderParameters, elem+20, "uint") = 6) - - ; struct EncoderParameter - http://www.jose.it-berater.org/gdiplus/reference/structures/encoderparameter.htm - ep := EncoderParameters.ptr + elem - A_PtrSize ; sizeof(EncoderParameter) = 28, 32 - NumPut( "uptr", 1, ep) ; Must be 1. - NumPut( "uint", 4, ep, 20+A_PtrSize) ; Type - NumPut( "uint", quality, NumGet(ep+24+A_PtrSize, "uptr")) ; Value (pointer) - } + ; Select the proper codec based on the extension of the file. + this.select_codec(pBitmap, extension, quality, &pCodec, &ep) ; Create a Stream. DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "int", true, "ptr*", &pStream:=0) @@ -1747,6 +1683,43 @@ class ImagePut { return StrGet(base64, length, "CP0") } + static select_codec(pBitmap, extension, quality, &pCodec, &ep) { + ; Fill a buffer with the available encoders. + DllCall("gdiplus\GdipGetImageEncodersSize", "uint*", &count:=0, "uint*", &size:=0) + ci := Buffer(size) + DllCall("gdiplus\GdipGetImageEncoders", "uint", count, "uint", size, "ptr", ci) + if !(count && size) + throw Error("Could not get a list of image codec encoders on this system.") + + ; Search for an encoder with a matching extension. + loop count + EncoderExtensions := StrGet(NumGet(ci, (idx:=(48+7*A_PtrSize)*(A_Index-1))+32+3*A_PtrSize, "uptr"), "UTF-16") + until InStr(EncoderExtensions, "*." extension) + + ; Get the pointer to the index/offset of the matching encoder. + if !(pCodec := ci.ptr + idx) + throw Error("Could not find a matching encoder for the specified file format.") + + ; JPEG is a lossy image format that requires a quality value from 0-100. Default quality is 75. + if (extension ~= "^(?i:jpg|jpeg|jpe|jfif)$" + && IsInteger(quality) && 0 <= quality && quality <= 100 && quality != 75) { + DllCall("gdiplus\GdipGetEncoderParameterListSize", "ptr", pBitmap, "ptr", pCodec, "uint*", &size:=0) + EncoderParameters := Buffer(size, 0) + DllCall("gdiplus\GdipGetEncoderParameterList", "ptr", pBitmap, "ptr", pCodec, "uint", size, "ptr", EncoderParameters) + + ; Search for an encoder parameter with 1 value of type 6. + loop NumGet(EncoderParameters, "uint") + elem := (24+A_PtrSize)*(A_Index-1) + A_PtrSize + until (NumGet(EncoderParameters, elem+16, "uint") = 1) && (NumGet(EncoderParameters, elem+20, "uint") = 6) + + ; struct EncoderParameter - http://www.jose.it-berater.org/gdiplus/reference/structures/encoderparameter.htm + ep := EncoderParameters.ptr + elem - A_PtrSize ; sizeof(EncoderParameter) = 28, 32 + NumPut( "uptr", 1, ep, 0) ; Must be 1. + NumPut( "uint", 4, ep, 20+A_PtrSize) ; Type + NumPut( "uint", quality, NumGet(ep+24+A_PtrSize, "uptr")) ; Value (Set a pointer) + } + } + ; All references to gdiplus and pToken must be absolute! static gdiplus := 0, pToken := 0 From 6e902486ed18cf3931c676293a4f887d4207e1e0 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 27 Sep 2021 12:51:52 -0400 Subject: [PATCH 030/492] EncoderParameters now creates its own bugger --- ImagePut (for v1).ahk | 45 ++++++++++++++++++----------------------- ImagePut.ahk | 47 +++++++++++++++++++------------------------ 2 files changed, 41 insertions(+), 51 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 228c2b16..9ed52615 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1684,39 +1684,34 @@ class ImagePut { } select_codec(pBitmap, extension, quality, ByRef pCodec, ByRef ep) { - ; Fill a buffer with the available encoders. + static ci, v + ; Fill a buffer with the available image codec info. DllCall("gdiplus\GdipGetImageEncodersSize", "uint*", count:=0, "uint*", size:=0) - VarSetCapacity(ci, size) - DllCall("gdiplus\GdipGetImageEncoders", "uint", count, "uint", size, "ptr", &ci) - if !(count && size) - throw Exception("Could not get a list of image codec encoders on this system.") + DllCall("gdiplus\GdipGetImageEncoders", "uint", count, "uint", size, "ptr", &ci := VarSetCapacity(ci, size)) - ; Search for an encoder with a matching extension. + ; struct ImageCodecInfo - http://www.jose.it-berater.org/gdiplus/reference/structures/imagecodecinfo.htm loop % count - EncoderExtensions := StrGet(NumGet(ci, (idx:=(48+7*A_PtrSize)*(A_Index-1))+32+3*A_PtrSize, "uptr"), "UTF-16") - until InStr(EncoderExtensions, "*." extension) + idx := (48+7*A_PtrSize)*(A_Index-1) + until InStr(StrGet(NumGet(ci, idx+32+3*A_PtrSize, "ptr"), "UTF-16"), "*." extension) ; FilenameExtension - ; Get the pointer to the index/offset of the matching encoder. - if !(pCodec := &ci + idx) + ; Get the pointer to the clsid of the matching encoder. + if !(pCodec := &ci + idx) ; ClassID throw Exception("Could not find a matching encoder for the specified file format.") - ; JPEG is a lossy image format that requires a quality value from 0-100. Default quality is 75. - if (extension ~= "^(?i:jpg|jpeg|jpe|jfif)$" - && quality ~= "^\d+$" && 0 <= quality && quality <= 100 && quality != 75) { - DllCall("gdiplus\GdipGetEncoderParameterListSize", "ptr", pBitmap, "ptr", pCodec, "uint*", size:=0) - VarSetCapacity(EncoderParameters, size, 0) - DllCall("gdiplus\GdipGetEncoderParameterList", "ptr", pBitmap, "ptr", pCodec, "uint", size, "ptr", &EncoderParameters) - - ; Search for an encoder parameter with 1 value of type 6. - loop % NumGet(EncoderParameters, "uint") - elem := (24+A_PtrSize)*(A_Index-1) + A_PtrSize - until (NumGet(EncoderParameters, elem+16, "uint") = 1) && (NumGet(EncoderParameters, elem+20, "uint") = 6) + ; JPEG default quality is 75. Otherwise set a quality value from [0-100]. + if quality ~= "^\d+$" && ("image/jpeg" = StrGet(NumGet(ci, idx+32+4*A_PtrSize, "ptr"), "UTF-16")) { ; MimeType + ; Use a separate buffer to store the quality as ValueTypeLong (4). + VarSetCapacity(v, 4, 0), NumPut(quality, v, "uint") ; struct EncoderParameter - http://www.jose.it-berater.org/gdiplus/reference/structures/encoderparameter.htm - ep := &EncoderParameters + elem - A_PtrSize ; sizeof(EncoderParameter) = 28, 32 - NumPut( 1, ep+0, 0, "uptr") ; Must be 1. - NumPut( 4, ep+0, 20+A_PtrSize, "uint") ; Type - NumPut(quality, NumGet(ep+24+A_PtrSize, "uptr"), "uint") ; Value (Set a pointer) + ; enum ValueType - https://docs.microsoft.com/en-us/dotnet/api/system.drawing.imaging.encoderparametervaluetype + ; clsid Image Encoder Constants - http://www.jose.it-berater.org/gdiplus/reference/constants/gdipimageencoderconstants.htm + VarSetCapacity(ep, 24+2*A_PtrSize) ; sizeof(EncoderParameter) = ptr + n*(28, 32) + NumPut( 1, ep, 0, "uptr") ; Count + DllCall("ole32\CLSIDFromString", "wstr", "{1D5BE4B5-FA4A-452D-9CDD-5DB35105E7EB}", "ptr", &ep+A_PtrSize) + NumPut( 1, ep, 16+A_PtrSize, "uint") ; Number of Values + NumPut( 4, ep, 20+A_PtrSize, "uint") ; Type + NumPut( &v, ep, 24+A_PtrSize, "ptr") ; Value } } diff --git a/ImagePut.ahk b/ImagePut.ahk index a4d88143..2259e5d3 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1542,7 +1542,7 @@ class ImagePut { ; Write the file to disk using the specified encoder and encoding parameters with exponential backoff. loop - if !DllCall("gdiplus\GdipSaveImageToFile", "ptr", pBitmap, "wstr", filepath, "ptr", pCodec, "uint", IsSet(ep) ? ep : 0) + if !DllCall("gdiplus\GdipSaveImageToFile", "ptr", pBitmap, "wstr", filepath, "ptr", pCodec, "ptr", IsSet(ep) ? ep : 0) break else if A_Index < 6 @@ -1684,39 +1684,34 @@ class ImagePut { } static select_codec(pBitmap, extension, quality, &pCodec, &ep) { - ; Fill a buffer with the available encoders. + static ci, v + ; Fill a buffer with the available image codec info. DllCall("gdiplus\GdipGetImageEncodersSize", "uint*", &count:=0, "uint*", &size:=0) - ci := Buffer(size) - DllCall("gdiplus\GdipGetImageEncoders", "uint", count, "uint", size, "ptr", ci) - if !(count && size) - throw Error("Could not get a list of image codec encoders on this system.") + DllCall("gdiplus\GdipGetImageEncoders", "uint", count, "uint", size, "ptr", ci := Buffer(size)) - ; Search for an encoder with a matching extension. + ; struct ImageCodecInfo - http://www.jose.it-berater.org/gdiplus/reference/structures/imagecodecinfo.htm loop count - EncoderExtensions := StrGet(NumGet(ci, (idx:=(48+7*A_PtrSize)*(A_Index-1))+32+3*A_PtrSize, "uptr"), "UTF-16") - until InStr(EncoderExtensions, "*." extension) + idx := (48+7*A_PtrSize)*(A_Index-1) + until InStr(StrGet(NumGet(ci, idx+32+3*A_PtrSize, "ptr"), "UTF-16"), "*." extension) ; FilenameExtension - ; Get the pointer to the index/offset of the matching encoder. - if !(pCodec := ci.ptr + idx) + ; Get the pointer to the clsid of the matching encoder. + if !(pCodec := ci.ptr + idx) ; ClassID throw Error("Could not find a matching encoder for the specified file format.") - ; JPEG is a lossy image format that requires a quality value from 0-100. Default quality is 75. - if (extension ~= "^(?i:jpg|jpeg|jpe|jfif)$" - && IsInteger(quality) && 0 <= quality && quality <= 100 && quality != 75) { - DllCall("gdiplus\GdipGetEncoderParameterListSize", "ptr", pBitmap, "ptr", pCodec, "uint*", &size:=0) - EncoderParameters := Buffer(size, 0) - DllCall("gdiplus\GdipGetEncoderParameterList", "ptr", pBitmap, "ptr", pCodec, "uint", size, "ptr", EncoderParameters) - - ; Search for an encoder parameter with 1 value of type 6. - loop NumGet(EncoderParameters, "uint") - elem := (24+A_PtrSize)*(A_Index-1) + A_PtrSize - until (NumGet(EncoderParameters, elem+16, "uint") = 1) && (NumGet(EncoderParameters, elem+20, "uint") = 6) + ; JPEG default quality is 75. Otherwise set a quality value from [0-100]. + if IsInteger(quality) && ("image/jpeg" = StrGet(NumGet(ci, idx+32+4*A_PtrSize, "ptr"), "UTF-16")) { ; MimeType + ; Use a separate buffer to store the quality as ValueTypeLong (4). + v := Buffer(4, 0), NumPut("uint", quality, v) ; struct EncoderParameter - http://www.jose.it-berater.org/gdiplus/reference/structures/encoderparameter.htm - ep := EncoderParameters.ptr + elem - A_PtrSize ; sizeof(EncoderParameter) = 28, 32 - NumPut( "uptr", 1, ep, 0) ; Must be 1. - NumPut( "uint", 4, ep, 20+A_PtrSize) ; Type - NumPut( "uint", quality, NumGet(ep+24+A_PtrSize, "uptr")) ; Value (Set a pointer) + ; enum ValueType - https://docs.microsoft.com/en-us/dotnet/api/system.drawing.imaging.encoderparametervaluetype + ; clsid Image Encoder Constants - http://www.jose.it-berater.org/gdiplus/reference/constants/gdipimageencoderconstants.htm + ep := Buffer(24+2*A_PtrSize) ; sizeof(EncoderParameter) = ptr + n*(28, 32) + NumPut( "uptr", 1, ep, 0) ; Count + DllCall("ole32\CLSIDFromString", "wstr", "{1D5BE4B5-FA4A-452D-9CDD-5DB35105E7EB}", "ptr", ep.ptr+A_PtrSize) + NumPut( "uint", 1, ep, 16+A_PtrSize) ; Number of Values + NumPut( "uint", 4, ep, 20+A_PtrSize) ; Type + NumPut( "ptr", v.ptr, ep, 24+A_PtrSize) ; Value } } From 10ca7eeb942cf64001c01b2ae2cd0a8e02f86f87 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 27 Sep 2021 13:11:04 -0400 Subject: [PATCH 031/492] Fix missing &, ptr type, and negative quality --- ImagePut (for v1).ahk | 13 ++++++------- ImagePut.ahk | 9 ++++----- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 9ed52615..f4affc92 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1538,11 +1538,11 @@ class ImagePut { filepath := directory "\" filename "." extension ; Select the proper codec based on the extension of the file. - this.select_codec(pBitmap, extension, quality, pCodec, ep) + this.select_codec(pBitmap, extension, quality, pCodec, ep, ci, v) ; Write the file to disk using the specified encoder and encoding parameters with exponential backoff. loop - if !DllCall("gdiplus\GdipSaveImageToFile", "ptr", pBitmap, "wstr", filepath, "ptr", pCodec, "uint", (ep) ? ep : 0) + if !DllCall("gdiplus\GdipSaveImageToFile", "ptr", pBitmap, "wstr", filepath, "ptr", pCodec, "ptr", (ep) ? &ep : 0) break else if A_Index < 6 @@ -1608,11 +1608,11 @@ class ImagePut { extension := "tif" ; Select the proper codec based on the extension of the file. - this.select_codec(pBitmap, extension, quality, pCodec, ep) + this.select_codec(pBitmap, extension, quality, pCodec, ep, ci, v) ; Create a Stream. DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "int", true, "ptr*", pStream:=0) - DllCall("gdiplus\GdipSaveImageToStream", "ptr", pBitmap, "ptr", pStream, "ptr", pCodec, "uint", ep ? ep : 0) + DllCall("gdiplus\GdipSaveImageToStream", "ptr", pBitmap, "ptr", pStream, "ptr", pCodec, "ptr", ep ? ep : 0) return pStream } @@ -1683,8 +1683,7 @@ class ImagePut { return StrGet(&base64, length, "CP0") } - select_codec(pBitmap, extension, quality, ByRef pCodec, ByRef ep) { - static ci, v + select_codec(pBitmap, extension, quality, ByRef pCodec, ByRef ep, ByRef ci, ByRef v) { ; Fill a buffer with the available image codec info. DllCall("gdiplus\GdipGetImageEncodersSize", "uint*", count:=0, "uint*", size:=0) DllCall("gdiplus\GdipGetImageEncoders", "uint", count, "uint", size, "ptr", &ci := VarSetCapacity(ci, size)) @@ -1699,7 +1698,7 @@ class ImagePut { throw Exception("Could not find a matching encoder for the specified file format.") ; JPEG default quality is 75. Otherwise set a quality value from [0-100]. - if quality ~= "^\d+$" && ("image/jpeg" = StrGet(NumGet(ci, idx+32+4*A_PtrSize, "ptr"), "UTF-16")) { ; MimeType + if quality ~= "^-?\d+$" && ("image/jpeg" = StrGet(NumGet(ci, idx+32+4*A_PtrSize, "ptr"), "UTF-16")) { ; MimeType ; Use a separate buffer to store the quality as ValueTypeLong (4). VarSetCapacity(v, 4, 0), NumPut(quality, v, "uint") diff --git a/ImagePut.ahk b/ImagePut.ahk index 2259e5d3..111f5ddf 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1538,7 +1538,7 @@ class ImagePut { filepath := directory "\" filename "." extension ; Select the proper codec based on the extension of the file. - this.select_codec(pBitmap, extension, quality, &pCodec, &ep) + this.select_codec(pBitmap, extension, quality, &pCodec, &ep, &ci, &v) ; Write the file to disk using the specified encoder and encoding parameters with exponential backoff. loop @@ -1608,11 +1608,11 @@ class ImagePut { extension := "tif" ; Select the proper codec based on the extension of the file. - this.select_codec(pBitmap, extension, quality, &pCodec, &ep) + this.select_codec(pBitmap, extension, quality, &pCodec, &ep, &ci, &v) ; Create a Stream. DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "int", true, "ptr*", &pStream:=0) - DllCall("gdiplus\GdipSaveImageToStream", "ptr", pBitmap, "ptr", pStream, "ptr", pCodec, "uint", IsSet(ep) ? ep : 0) + DllCall("gdiplus\GdipSaveImageToStream", "ptr", pBitmap, "ptr", pStream, "ptr", pCodec, "ptr", IsSet(ep) ? ep : 0) return pStream } @@ -1683,8 +1683,7 @@ class ImagePut { return StrGet(base64, length, "CP0") } - static select_codec(pBitmap, extension, quality, &pCodec, &ep) { - static ci, v + static select_codec(pBitmap, extension, quality, &pCodec, &ep, &ci, &v) { ; Fill a buffer with the available image codec info. DllCall("gdiplus\GdipGetImageEncodersSize", "uint*", &count:=0, "uint*", &size:=0) DllCall("gdiplus\GdipGetImageEncoders", "uint", count, "uint", size, "ptr", ci := Buffer(size)) From 7f4865479b05c1bc5cccadc73187e75b13dfe25f Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 27 Sep 2021 22:38:03 -0400 Subject: [PATCH 032/492] Fix put_stream() missing & in v1 --- ImagePut (for v1).ahk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index f4affc92..6209bea0 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1612,7 +1612,7 @@ class ImagePut { ; Create a Stream. DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "int", true, "ptr*", pStream:=0) - DllCall("gdiplus\GdipSaveImageToStream", "ptr", pBitmap, "ptr", pStream, "ptr", pCodec, "ptr", ep ? ep : 0) + DllCall("gdiplus\GdipSaveImageToStream", "ptr", pBitmap, "ptr", pStream, "ptr", pCodec, "ptr", (ep) ? &ep : 0) return pStream } From 265da0a3d37ec3f5aef37796114d38e75bab2810 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 28 Sep 2021 10:21:29 -0400 Subject: [PATCH 033/492] GlobalFree should not double free a stream ObjRelease() will free the underlying hGlobal when fDeleteOnRelease is set to true. --- ImagePut (for v1).ahk | 2 -- ImagePut.ahk | 2 -- 2 files changed, 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 6209bea0..f5655d64 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1653,7 +1653,6 @@ class ImagePut { DllCall("Crypt32.dll\CryptBinaryToStringA", "ptr", pData, "uint", nSize, "uint", 0x4000000C, "ptr", &hex, "uint*", length) DllCall("GlobalUnlock", "ptr", hData) - DllCall("GlobalFree", "ptr", hData) ObjRelease(pStream) return StrGet(&hex, length, "CP0") @@ -1677,7 +1676,6 @@ class ImagePut { DllCall("Crypt32.dll\CryptBinaryToStringA", "ptr", pData, "uint", nSize, "uint", 0x40000001, "ptr", &base64, "uint*", length) DllCall("GlobalUnlock", "ptr", hData) - DllCall("GlobalFree", "ptr", hData) ObjRelease(pStream) return StrGet(&base64, length, "CP0") diff --git a/ImagePut.ahk b/ImagePut.ahk index 111f5ddf..a02e0f98 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1653,7 +1653,6 @@ class ImagePut { DllCall("Crypt32.dll\CryptBinaryToStringA", "ptr", pData, "uint", nSize, "uint", 0x4000000C, "ptr", hex, "uint*", length) DllCall("GlobalUnlock", "ptr", hData) - DllCall("GlobalFree", "ptr", hData) ObjRelease(pStream) return StrGet(hex, length, "CP0") @@ -1677,7 +1676,6 @@ class ImagePut { DllCall("Crypt32.dll\CryptBinaryToStringA", "ptr", pData, "uint", nSize, "uint", 0x40000001, "ptr", base64, "uint*", length) DllCall("GlobalUnlock", "ptr", hData) - DllCall("GlobalFree", "ptr", hData) ObjRelease(pStream) return StrGet(base64, length, "CP0") From 88a2b6b7f7441572fab7253c513a42d7bc5a0a67 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 28 Sep 2021 20:47:22 -0400 Subject: [PATCH 034/492] v1.1 --- ImagePut (for v1).ahk | 4 ++-- ImagePut.ahk | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index f5655d64..e7060e8e 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1,8 +1,8 @@ ; Script: ImagePut.ahk ; License: MIT License ; Author: Edison Hua (iseahound) -; Date: 2021-05-17 -; Version: v1.00 +; Date: 2021-09-28 +; Version: v1.1 #Requires AutoHotkey v1.1.33+ diff --git a/ImagePut.ahk b/ImagePut.ahk index a02e0f98..d951b712 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1,8 +1,8 @@ ; Script: ImagePut.ahk ; License: MIT License ; Author: Edison Hua (iseahound) -; Date: 2021-05-17 -; Version: v1.00 +; Date: 2021-09-28 +; Version: v1.1 #Requires AutoHotkey v2-a134+ From 7ec58eaddb1c003653093b9a9ab49dc80637d6e7 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 2 Oct 2021 21:03:55 -0400 Subject: [PATCH 035/492] Proof + Refactor entire script to use streams --- ImagePut (for v1).ahk | 686 +++++++++++++++++++++++++++--------------- 1 file changed, 440 insertions(+), 246 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index e7060e8e..29783b51 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -106,12 +106,18 @@ ImagePut(cotype, image, crop := "", scale := "", terms*) { class ImagePut { + ; If true the conversion will always go through a GDI+ Bitmap and the original file encoding will be lost. + static ForceDecodeImagePixels := false + + ; If true the pBitmap will always be filled with image data instead of referencing it and copying when needed. + static ForcePushImageToMemory := false + ; ImagePut() - Puts an image from anywhere to anywhere. ; cotype - Output Type | string -> Case Insensitive. Read documentation. ; image - Input Image | image -> Anything. Refer to ImageType(). ; crop - Crop Coordinates | array -> [x,y,w,h] could be negative or percent. ; scale - Scale Factor | real -> 2.0 - ; terms* - Additional Parameters | variadic -> Extra parameters found in toCotype(). + ; terms* - Additional Parameters | variadic -> Extra parameters found in BitmapToCoimage(). call(cotype, image, crop := "", scale := "", terms*) { this.gdiplusStartup() @@ -127,36 +133,63 @@ class ImagePut { && crop[3] ~= "^-?\d+(\.\d*)?%?$" && crop[4] ~= "^-?\d+(\.\d*)?%?$" _scale := scale != 1 && scale ~= "^\d+(\.\d+)?$" - ; Make a copy of the image as a pBitmap. - pBitmap := this.toBitmap(type, image) + if not this.ForceDecodeImagePixels and not _crop and not _scale + and (type ~= "^(?i:url|file|stream|RandomAccessStream|hex|base64)$") + and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64)$") { - ; Crop the image. - if (_crop) { - pBitmap2 := this.BitmapCrop(pBitmap, crop) - DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) - pBitmap := pBitmap2 - } + ; Convert to a stream intermediate then to the output coimage. + pStream := this.ToStream(type, image) + coimage := this.StreamToCoimage(cotype, pStream, terms*) + + ; Prevents the stream object from being freed. + if (cotype = "stream") + ObjAddRef(pStream) - ; Scale the image. - if (_scale) { - pBitmap2 := this.BitmapScale(pBitmap, scale) - DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) - pBitmap := pBitmap2 + ; Free the temporary stream object. + ObjRelease(pStream) + + return coimage } + else { + ; Make a copy of the image as a pBitmap. + pBitmap := this.ToBitmap(type, image) + + ; Load the image pixels to the bitmap buffer. + ; This increases memory usage but prevents any changes to the pixels, + ; and bypasses any copy-on-write and copy on LockBits read behavior. + ; This must be called immediately after the pBitmap is created + ; or it will fail without throwing any errors. + if (this.ForcePushImageToMemory) + DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmap) + + ; Crop the image. + if (_crop) { + pBitmap2 := this.BitmapCrop(pBitmap, crop) + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + pBitmap := pBitmap2 + } - ; Put the pBitmap to wherever the cotype specifies. - coimage := this.toCotype(cotype, pBitmap, terms*) + ; Scale the image. + if (_scale) { + pBitmap2 := this.BitmapScale(pBitmap, scale) + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + pBitmap := pBitmap2 + } - ; Clean up the pBitmap copy. Export raw pointers if requested. - if !(cotype = "bitmap" || cotype = "buffer") - DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + ; Put the pBitmap to wherever the cotype specifies. + coimage := this.BitmapToCoimage(cotype, pBitmap, terms*) + + ; Clean up the pBitmap copy. Export raw pointers if requested. + if !(cotype = "bitmap" || cotype = "buffer") + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + } this.gdiplusShutdown(cotype) return coimage } - DontVerifyImageType(image) { + DontVerifyImageType(ByRef image) { if !IsObject(image) throw Exception("Must be an object.") @@ -264,7 +297,7 @@ class ImagePut { ImageType(image) { if (image == "") { - DllCall("OpenClipboard", "ptr", 0) + DllCall("OpenClipboard", "ptr", A_ScriptHwnd) result := !DllCall("IsClipboardFormatAvailable", "uint", DllCall("RegisterClipboardFormat", "str", "png", "uint")) && !DllCall("IsClipboardFormatAvailable", "uint", 2) DllCall("CloseClipboard") if !(result) @@ -328,7 +361,7 @@ class ImagePut { ; Note 1: All GDI+ functions add 1 to the reference count of COM objects. ; Note 2: GDI+ pBitmaps that are queried cease to stay pBitmaps. - ObjRelease(image) + ObjRelease(image) ; Therefore do not move this, it has been tested. ; A "stream" is a pointer to the IStream interface. try if ComObjQuery(image, "{0000000C-0000-0000-C000-000000000046}") @@ -356,7 +389,7 @@ class ImagePut { throw Exception("Image type could not be identified.") } - toBitmap(type, image) { + ToBitmap(type, image) { if (type = "clipboard") return this.from_clipboard() @@ -415,75 +448,122 @@ class ImagePut { if (type = "sprite") return this.from_sprite(image) - throw Exception("Conversion from type " type " is not supported.") + throw Exception("Conversion from " type " to bitmap is not supported.") } - toCotype(cotype, pBitmap, term1 := "", term2 := "", _*) { - ; toCotype("clipboard", pBitmap) + BitmapToCoimage(cotype, pBitmap, p1 := "", p2 := "", p*) { + ; BitmapToCoimage("clipboard", pBitmap) if (cotype = "clipboard") return this.put_clipboard(pBitmap) - ; toCotype("buffer", pBitmap) + ; BitmapToCoimage("buffer", pBitmap) if (cotype = "buffer") return this.put_buffer(pBitmap) - ; toCotype("screenshot", pBitmap, screenshot, alpha) + ; BitmapToCoimage("screenshot", pBitmap, screenshot, alpha) if (cotype = "screenshot") - return this.put_screenshot(pBitmap, term1, term2) + return this.put_screenshot(pBitmap, p1, p2) - ; toCotype("window", pBitmap, title) + ; BitmapToCoimage("window", pBitmap, title) if (cotype = "window") - return this.put_window(pBitmap, term1) + return this.put_window(pBitmap, p1) - ; toCotype("desktop", pBitmap) + ; BitmapToCoimage("desktop", pBitmap) if (cotype = "desktop") return this.put_desktop(pBitmap) - ; toCotype("wallpaper", pBitmap) + ; BitmapToCoimage("wallpaper", pBitmap) if (cotype = "wallpaper") return this.put_wallpaper(pBitmap) - ; toCotype("cursor", pBitmap, xHotspot, yHotspot) + ; BitmapToCoimage("cursor", pBitmap, xHotspot, yHotspot) if (cotype = "cursor") - return this.put_cursor(pBitmap, term1, term2) + return this.put_cursor(pBitmap, p1, p2) - ; toCotype("url", pBitmap) + ; BitmapToCoimage("url", pBitmap) if (cotype = "url") return this.put_url(pBitmap) - ; toCotype("file", pBitmap, filename, quality) + ; BitmapToCoimage("file", pBitmap, filepath, quality) if (cotype = "file") - return this.put_file(pBitmap, term1, term2) + return this.put_file(pBitmap, p1, p2) - ; toCotype("hBitmap", pBitmap, alpha) + ; BitmapToCoimage("hBitmap", pBitmap, alpha) if (cotype = "hBitmap") - return this.put_hBitmap(pBitmap, term1) + return this.put_hBitmap(pBitmap, p1) - ; toCotype("hIcon", pBitmap) + ; BitmapToCoimage("hIcon", pBitmap) if (cotype = "hIcon") return this.put_hIcon(pBitmap) - ; toCotype("bitmap", pBitmap) + ; BitmapToCoimage("bitmap", pBitmap) if (cotype = "bitmap") return pBitmap - ; toCotype("stream", pBitmap, extension, quality) + ; BitmapToCoimage("stream", pBitmap, extension, quality) if (cotype = "stream") - return this.put_stream(pBitmap, term1, term2) + return this.put_stream(pBitmap, p1, p2) - ; toCotype("RandomAccessStream", pBitmap, extension, quality) + ; BitmapToCoimage("RandomAccessStream", pBitmap, extension, quality) if (cotype = "RandomAccessStream") - return this.put_RandomAccessStream(pBitmap, term1, term2) + return this.put_RandomAccessStream(pBitmap, p1, p2) - ; toCotype("hex", pBitmap, extension, quality) + ; BitmapToCoimage("hex", pBitmap, extension, quality) if (cotype = "hex") - return this.put_hex(pBitmap, term1, term2) + return this.put_hex(pBitmap, p1, p2) - ; toCotype("base64", pBitmap, extension, quality) + ; BitmapToCoimage("base64", pBitmap, extension, quality) if (cotype = "base64") - return this.put_base64(pBitmap, term1, term2) + return this.put_base64(pBitmap, p1, p2) - throw Exception("Conversion to type " cotype " is not supported.") + throw Exception("Conversion from bitmap to " cotype " is not supported.") + } + + ToStream(type, image) { + + if (type = "url") + return this.get_url(image) + + if (type = "file") + return this.get_file(image) + + if (type = "stream") + return this.get_stream(image) + + if (type = "RandomAccessStream") + return this.get_RandomAccessStream(image) + + if (type = "hex") + return this.get_hex(image) + + if (type = "base64") + return this.get_base64(image) + + throw Exception("Conversion from " type " to stream is not supported.") + } + + StreamToCoimage(cotype, pStream, p1 := "", p2 := "", p*) { + ; StreamToCoimage("file", pStream, filepath) + if (cotype = "file") + return this.set_file(pStream, p1) + + ; StreamToCoimage("stream", pStream) + if (cotype = "stream") + return pStream + + ; StreamToCoimage("RandomAccessStream", pStream) + if (cotype = "RandomAccessStream") + return this.set_RandomAccessStream(pStream) + + ; StreamToCoimage("hex", pStream) + if (cotype = "hex") + return this.set_hex(pStream) + + ; StreamToCoimage("base64", pStream) + if (cotype = "base64") + return this.set_base64(pStream) + + throw Exception("Conversion from bitmap to " cotype " is not supported.") } DisposeImage(pBitmap) { @@ -611,30 +691,35 @@ class ImagePut { from_clipboard() { ; Open the clipboard with exponential backoff. loop - if DllCall("OpenClipboard", "ptr", 0) + if DllCall("OpenClipboard", "ptr", A_ScriptHwnd) break else if A_Index < 6 Sleep (2**(A_Index-1) * 30) else throw Exception("Clipboard could not be opened.") - ; Prefer the PNG stream if available considering it supports transparency. + ; Prefer the PNG stream if available because of transparency support. png := DllCall("RegisterClipboardFormat", "str", "png", "uint") if DllCall("IsClipboardFormatAvailable", "uint", png, "int") { - hData := DllCall("GetClipboardData", "uint", png, "ptr") - DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", true, "ptr*", pStream:=0) + if !(hData := DllCall("GetClipboardData", "uint", png, "ptr")) + throw Exception("Shared clipboard data has been deleted.") + DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", true, "ptr*", pStream:=0, "uint") DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", pBitmap:=0) - ObjRelease(pStream) + ; DO NOT RELEASE THE STREAM. CLIPBOARD IS SHARED MEMORY IF YOU RELEASE IT WILL BE DELETED. } ; Fallback to CF_BITMAP. This format does not support transparency even with put_hBitmap(). else if DllCall("IsClipboardFormatAvailable", "uint", 2, "int") { - hBitmap := DllCall("GetClipboardData", "uint", 2, "ptr") + if !(hBitmap := DllCall("GetClipboardData", "uint", 2, "ptr")) + throw Exception("Shared clipboard data has been deleted.") DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "ptr", hBitmap, "ptr", 0, "ptr*", pBitmap:=0) DllCall("DeleteObject", "ptr", hBitmap) } - DllCall("CloseClipboard") + ; Close the clipboard. + if !DllCall("CloseClipboard") + throw Exception("Clipboard could not be closed.") + return pBitmap } @@ -829,13 +914,18 @@ class ImagePut { } from_url(image) { + pStream := this.get_url(image) + DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", pBitmap:=0) + ObjRelease(pStream) + return pBitmap + } + + get_url(image) { req := ComObjCreate("WinHttp.WinHttpRequest.5.1") req.Open("GET", image) req.Send() pStream := ComObjQuery(req.ResponseStream, "{0000000C-0000-0000-C000-000000000046}") - DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", pBitmap:=0) - ObjRelease(pStream) - return pBitmap + return pStream } from_file(image) { @@ -843,6 +933,17 @@ class ImagePut { return pBitmap } + get_file(image) { + file := FileOpen(image, "r") + hData := DllCall("GlobalAlloc", "uint", 0x2, "uptr", file.length, "ptr") + pData := DllCall("GlobalLock", "ptr", hData, "ptr") + file.RawRead(pData+0, file.length) + DllCall("GlobalUnlock", "ptr", hData) + file.Close() + DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", true, "ptr*", pStream:=0, "uint") + return pStream + } + from_monitor(image) { if (image > 0) { SysGet _, Monitor, image @@ -932,7 +1033,7 @@ class ImagePut { from_hIcon(image) { ; struct ICONINFO - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-iconinfo - VarSetCapacity(ii, 8+3*A_PtrSize, 0) ; sizeof(ICONINFO) = 20, 32 + VarSetCapacity(ii, 8+3*A_PtrSize) ; sizeof(ICONINFO) = 20, 32 DllCall("GetIconInfo", "ptr", image, "ptr", &ii) ; xHotspot := NumGet(ii, 4, "uint") ; yHotspot := NumGet(ii, 8, "uint") @@ -1007,62 +1108,69 @@ class ImagePut { return pBitmap } + get_stream(image) { + ; Creates a new, separate stream. Necessary to separate reference counting through a clone. + DllCall(IStream_Clone := NumGet(NumGet(image+0)+13*A_PtrSize), "ptr", image, "ptr*", pStream:=0) + return pStream + } + from_RandomAccessStream(image) { - ; Get the Class ID from a GUID string. - VarSetCapacity(CLSID, 16, 0) - if result := DllCall("ole32\CLSIDFromString", "wstr", "{0000000C-0000-0000-C000-000000000046}", "ptr", &CLSID, "uint") - throw Exception("CLSIDFromString failed. Error: " . Format("{:#x}", result)) + ; Creating a Bitmap from stream adds +3 to the reference count until DisposeImage is called. + pStream := this.get_RandomAccessStream(image) + DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", pBitmap:=0) + ObjRelease(pStream) + return pBitmap + } - ; Convert RandomAccessStream to stream. + get_RandomAccessStream(image) { + ; Note that the returned stream shares a reference count with the original RandomAccessStream. + VarSetCapacity(CLSID, 16) + DllCall("ole32\CLSIDFromString", "wstr", "{0000000C-0000-0000-C000-000000000046}", "ptr", &CLSID, "uint") DllCall("ShCore\CreateStreamOverRandomAccessStream", "ptr", image, "ptr", &CLSID, "ptr*", pStream:=0, "uint") + return pStream + } - ; Read stream to pBitmap. + from_hex(image) { + pStream := this.get_hex(image) DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", pBitmap:=0) - - ; Manually free the pointer to an IStream. ObjRelease(pStream) - return pBitmap } - from_hex(image) { - ; Trim whitespace and remove header. + get_hex(image) { image := Trim(image) image := RegExReplace(image, "^(0[xX])") + return this.get_string(image, 0xC) ; CRYPT_STRING_HEXRAW + } - ; Converts the image to binary data by first asking for the size. - DllCall("crypt32\CryptStringToBinary" - , "ptr", &image, "uint", 0, "uint", 0xC, "ptr", 0, "uint*", size:=0, "ptr", 0, "ptr", 0) - VarSetCapacity(bin, size, 0) - DllCall("crypt32\CryptStringToBinary" - , "ptr", &image, "uint", 0, "uint", 0xC, "ptr", &bin, "uint*", size, "ptr", 0, "ptr", 0) - - ; Makes a stream for conversion into a pBitmap. - pStream := DllCall("shlwapi\SHCreateMemStream", "ptr", &bin, "uint", size, "ptr") + from_base64(image) { + pStream := this.get_base64(image) DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", pBitmap:=0) ObjRelease(pStream) - return pBitmap } - from_base64(image) { - ; Trim whitespace and remove header. + get_base64(image) { image := Trim(image) image := RegExReplace(image, "^data:image\/[a-z]+;base64,") + return this.get_string(image, 0x1) ; CRYPT_STRING_BASE64 + } - ; Converts the image to binary data by first asking for the size. + get_string(image, flags) { + ; Ask for the size. Then allocate movable memory, copy to the buffer, unlock, and create stream. DllCall("crypt32\CryptStringToBinary" - , "ptr", &image, "uint", 0, "uint", 0x1, "ptr", 0, "uint*", size:=0, "ptr", 0, "ptr", 0) - VarSetCapacity(bin, size, 0) + , "ptr", &image, "uint", 0, "uint", flags, "ptr", 0, "uint*", size:=0, "ptr", 0, "ptr", 0) + + hData := DllCall("GlobalAlloc", "uint", 0x2, "uptr", size, "ptr") + pData := DllCall("GlobalLock", "ptr", hData, "ptr") + DllCall("crypt32\CryptStringToBinary" - , "ptr", &image, "uint", 0, "uint", 0x1, "ptr", &bin, "uint*", size, "ptr", 0, "ptr", 0) + , "ptr", &image, "uint", 0, "uint", flags, "ptr", pData, "uint*", size, "ptr", 0, "ptr", 0) - ; Makes a stream for conversion into a pBitmap. - pStream := DllCall("shlwapi\SHCreateMemStream", "ptr", &bin, "uint", size, "ptr") - DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", pBitmap:=0) - ObjRelease(pStream) + DllCall("GlobalUnlock", "ptr", hData) + DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", true, "ptr*", pStream:=0, "uint") - return pBitmap + return pStream } from_sprite(image) { @@ -1115,75 +1223,59 @@ class ImagePut { ; Open the clipboard with exponential backoff. loop - if DllCall("OpenClipboard", "ptr", 0) + if DllCall("OpenClipboard", "ptr", A_ScriptHwnd) break else if A_Index < 6 Sleep (2**(A_Index-1) * 30) else throw Exception("Clipboard could not be opened.") - ; Clear the clipboard. + ; If not opened with a valid window handle EmptyClipboard will crash the next call to OpenClipboard. DllCall("EmptyClipboard") ; #1 - Place the image onto the clipboard as a PNG stream. ; Thanks Jochen Arndt - https://www.codeproject.com/Answers/1207927/Saving-an-image-to-the-clipboard#answer3 pStream := this.put_stream(pBitmap, "png") - DllCall("ole32\GetHGlobalFromStream", "ptr", pStream, "uint*", hData:=0) - DllCall("SetClipboardData", "uint", DllCall("RegisterClipboardFormat", "str", "png", "uint"), "ptr", hData) - ObjRelease(pStream) + DllCall("ole32\GetHGlobalFromStream", "ptr", pStream, "uint*", hData:=0, "uint") + png := DllCall("RegisterClipboardFormat", "str", "png", "uint") ; case insensitive + DllCall("SetClipboardData", "uint", png, "ptr", hData) + ; DO NOT RELEASE THE STREAM. CLIPBOARD IS SHARED MEMORY IF YOU RELEASE IT WILL BE DELETED. - ; #2 - Place the image onto the clipboard in the CF_DIB format in ARGB using 3 color masks. (Extra 12 byte offset.) - ; Thanks Nyerguds - https://stackoverflow.com/a/46424800 + ; #2 - Place the image onto the clipboard in the CF_DIB format using a bottom-up bitmap. + ; Thanks tic - https://www.autohotkey.com/boards/viewtopic.php?t=6517 + DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", "ptr", pBitmap, "ptr*", hBitmap:=0, "uint", 0) - ; Get Bitmap width, height, and format. - DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) - DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) - DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", pBitmap, "uint*", format:=0) + ; struct DIBSECTION - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-dibsection + ; struct BITMAP - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmap + VarSetCapacity(dib, size := 64+5*A_PtrSize) ; sizeof(DIBSECTION) = 84, 104 + DllCall("GetObject", "ptr", hBitmap, "int", size, "ptr", &dib) - ; Get Bitmap bits per pixel, stride, and size. - bpp := (format & 0x00FF00) >> 8 - stride := (bpp >> 3) * width - size := stride * height + ; Find the pointer to the bitmap bits and the size of the bitmap bits. + pBits := NumGet(dib, A_PtrSize = 4 ? 20:24, "ptr") ; bmBits + size := NumGet(dib, A_PtrSize = 4 ? 44:52, "uint") ; biSizeImage - ; struct DIBSECTION - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-dibsection - ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader - hdib := DllCall("GlobalAlloc", "uint", 0x42, "uptr", 40 + 12 + size, "ptr") + ; Allocate space for a new device independent bitmap on movable memory. + hdib := DllCall("GlobalAlloc", "uint", 0x2, "uptr", 40 + size, "ptr") ; sizeof(BITMAPINFOHEADER) = 40 pdib := DllCall("GlobalLock", "ptr", hdib, "ptr") - NumPut( 40, pdib+0, 0, "uint") ; Size - NumPut( width, pdib+0, 4, "int") ; Width - NumPut( -height, pdib+0, 8, "int") ; Height - Negative so (0, 0) is top-left. - NumPut( 1, pdib+0, 12, "ushort") ; Planes - NumPut( bpp, pdib+0, 14, "ushort") ; BitCount / BitsPerPixel - NumPut( 0x3, pdib+0, 16, "uint") ; Compression - NumPut( size, pdib+0, 20, "uint") ; SizeImage (bytes) - ; The following bitfields when masked extract the respective color channels. - NumPut(0x00FF0000, pdib+0, 40, "uint") ; Red - NumPut(0x0000FF00, pdib+0, 44, "uint") ; Green - NumPut(0x000000FF, pdib+0, 48, "uint") ; Blue - - ; Transfer data from source pBitmap to the global memory manually. - VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 - NumPut( width, Rect, 8, "uint") ; Width - NumPut( height, Rect, 12, "uint") ; Height - VarSetCapacity(BitmapData, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 - NumPut( stride, BitmapData, 8, "int") ; Stride - NumPut( pdib + 52, BitmapData, 16, "ptr") ; Scan0 - DllCall("gdiplus\GdipBitmapLockBits" - , "ptr", pBitmap - , "ptr", &Rect - , "uint", 5 ; ImageLockMode.UserInputBuffer | ImageLockMode.ReadOnly - , "int", 0x26200A ; Format32bppArgb - , "ptr", &BitmapData) ; Contains the pointer (pdib) to the hData. - DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", &BitmapData) - ; Unlock the memory as it is complete. + ; Copy the BITMAPINFOHEADER from the old DIB to the new DIB. + DllCall("RtlMoveMemory", "ptr", pdib, "ptr", &dib + (A_PtrSize = 4 ? 24:32), "uptr", 40) + + ; Copy the pixel data from the old DIB to the new DIB. + DllCall("RtlMoveMemory", "ptr", pdib+40, "ptr", pBits, "uptr", size) + + ; Unlock to moveable memory because the clipboard requires it. DllCall("GlobalUnlock", "ptr", hdib) - ; Add CF_DIB as a format to the clipboard. + ; Delete the temporary hBitmap. + DllCall("DeleteObject", "ptr", hBitmap) + + ; CF_DIB (8) can be synthesized into CF_BITMAP (2), CF_PALETTE (9), and CF_DIBV5 (17). DllCall("SetClipboardData", "uint", 8, "ptr", hdib) ; Close the clipboard. - DllCall("CloseClipboard") + if !DllCall("CloseClipboard") + throw Exception("Clipboard could not be closed.") return "" } @@ -1274,7 +1366,7 @@ class ImagePut { ; struct tagWNDCLASSEXA - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexa ; struct tagWNDCLASSEXW - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexw _ := (A_PtrSize = 4) - VarSetCapacity(wc, size := _ ? 48:80, 0) ; sizeof(WNDCLASSEX) = 48, 80 + VarSetCapacity(wc, size := _ ? 48:80) ; sizeof(WNDCLASSEX) = 48, 80 NumPut( size, wc, 0, "uint") ; cbSize NumPut( 0, wc, 4, "uint") ; style NumPut( pWndProc, wc, 8, "ptr") ; lpfnWndProc @@ -1309,7 +1401,7 @@ class ImagePut { WS_EX_TRANSPARENT := 0x20 WS_EX_DLGMODALFRAME := 0x1 - VarSetCapacity(rect, 16, 0) + VarSetCapacity(rect, 16) NumPut(Floor((A_ScreenWidth - width) / 2), rect, 0, "int") NumPut(Floor((A_ScreenHeight - height) / 2), rect, 4, "int") NumPut(Floor((A_ScreenWidth + width) / 2), rect, 8, "int") @@ -1460,7 +1552,7 @@ class ImagePut { else throw Exception("Unable to create temporary image file.") ; Set the temporary image file as the new desktop wallpaper. - DllCall("SystemParametersInfo", "uint", 20, "uint", 0, "str", buf, "uint", 2) + DllCall("SystemParametersInfo", "uint", SPI_SETDESKWALLPAPER := 20, "uint", 0, "str", buf, "uint", 2) ; This is a delayed delete call. #Persistent may be required on v1. DeleteFile := Func("DllCall").Bind("DeleteFile", "str", filepath) @@ -1478,7 +1570,7 @@ class ImagePut { ; Sets the hotspot of the cursor by changing the icon into a cursor. if (xHotspot != "" || yHotspot != "") { ; struct ICONINFO - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-iconinfo - VarSetCapacity(ii, 8+3*A_PtrSize, 0) ; sizeof(ICONINFO) = 20, 32 + VarSetCapacity(ii, 8+3*A_PtrSize) ; sizeof(ICONINFO) = 20, 32 DllCall("GetIconInfo", "ptr", hIcon, "ptr", &ii) ; Fill the ICONINFO structure. NumPut(false, ii, 0, "uint") ; true/false are icon/cursor respectively. (xHotspot != "") ? NumPut(xHotspot, ii, 4, "uint") : "" ; Set the xHotspot value. (Default: center point) @@ -1508,34 +1600,8 @@ class ImagePut { put_file(pBitmap, filepath := "", quality := "") { ; Thanks tic - https://www.autohotkey.com/boards/viewtopic.php?t=6517 - - ; Remove whitespace. Seperate the filepath. Adjust for directories. - filepath := Trim(filepath) - SplitPath filepath,, directory, extension, filename - if InStr(FileExist(filepath), "D") - directory .= "\" filename, filename := "" - if (directory != "" && !InStr(FileExist(directory), "D")) - FileCreateDir % directory - directory := (directory != "") ? directory : "." - - ; Validate filepath, defaulting to PNG. https://stackoverflow.com/a/6804755 - if !(extension ~= "^(?i:bmp|dib|rle|jpg|jpeg|jpe|jfif|gif|tif|tiff|png)$") { - if (extension != "") - filename .= "." extension - extension := "png" - } - filename := RegExReplace(filename, "S)(?i:^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$|[<>:|?*\x00-\x1F\x22\/\\])") - if (filename == "") { - FormatTime, filename,, % "yyyy-MM-dd HH?mm?ss" - filepath := directory "\" filename "." extension - if FileExist(filepath) { ; Check for collisions. - loop - filepath := directory "\" filename " (" A_Index ")." extension - until !FileExist(filepath) - } - } - else - filepath := directory "\" filename "." extension + default := "png" + this.select_filepath(filepath, default) ; Select the proper codec based on the extension of the file. this.select_codec(pBitmap, extension, quality, pCodec, ep, ci, v) @@ -1552,6 +1618,27 @@ class ImagePut { return filepath } + set_file(pStream, filepath := "") { + default := "png" + this.select_filepath(filepath, default, pStream) + + ; For compatibility with SHCreateMemStream do not use GetHGlobalFromStream. + DllCall("shlwapi\SHCreateStreamOnFileEx" + , "wstr", filepath + , "uint", 0x1001 ; STGM_CREATE | STGM_WRITE + , "uint", 0x80 ; FILE_ATTRIBUTE_NORMAL + , "int", true ; fCreate is ignored when STGM_CREATE is set. + , "ptr", 0 ; pstmTemplate (reserved) + , "ptr*", pFileStream:=0 + , "uint") + DllCall("shlwapi\IStream_Size", "ptr", pStream, "ptr*", size:=0, "uint") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") + DllCall("shlwapi\IStream_Copy", "ptr", pStream, "ptr", pFileStream, "uint", size, "uint") + ObjRelease(pFileStream) + + return filepath + } + put_hBitmap(pBitmap, alpha := "") { ; Revert to built in functionality if a replacement color is declared. if (alpha != "") { ; This built-in version is about 25% slower. @@ -1611,29 +1698,29 @@ class ImagePut { this.select_codec(pBitmap, extension, quality, pCodec, ep, ci, v) ; Create a Stream. - DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "int", true, "ptr*", pStream:=0) + DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "int", true, "ptr*", pStream:=0, "uint") DllCall("gdiplus\GdipSaveImageToStream", "ptr", pBitmap, "ptr", pStream, "ptr", pCodec, "ptr", (ep) ? &ep : 0) return pStream } put_RandomAccessStream(pBitmap, extension := "", quality := "") { - ; Thanks teadrinker - https://www.autohotkey.com/boards/viewtopic.php?f=6&t=72674 - - ; Which is faster, bmp or png? pStream := this.put_stream(pBitmap, extension, quality) + pRandomAccessStream := this.set_RandomAccessStream(pStream) + ObjRelease(pStream) ; Decrement the reference count of the IStream interface. + return pRandomAccessStream + } - ; Get the Class ID from a GUID string. - VarSetCapacity(CLSID, 16, 0) - if result := DllCall("ole32\CLSIDFromString", "wstr", "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}", "ptr", &CLSID, "uint") - throw Exception("CLSIDFromString failed. Error: " . Format("{:#x}", result)) - - ; Create a RandomAccessStream - DllCall("ShCore\CreateRandomAccessStreamOverStream", "ptr", pStream, "uint", 1, "ptr", &CLSID, "ptr*", pRandomAccessStream:=0, "uint") - - ; The handle to the stream object is automatically freed when the stream object is released. - ObjRelease(pStream) - + set_RandomAccessStream(pStream) { + ; Thanks teadrinker - https://www.autohotkey.com/boards/viewtopic.php?f=6&t=72674 + VarSetCapacity(CLSID, 16) + DllCall("ole32\CLSIDFromString", "wstr", "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}", "ptr", &CLSID, "uint") + DllCall("ShCore\CreateRandomAccessStreamOverStream" + , "ptr", pStream + , "uint", BSOS_PREFERDESTINATIONSTREAM := 1 + , "ptr", &CLSID + , "ptr*", pRandomAccessStream:=0 + , "uint") return pRandomAccessStream } @@ -1643,42 +1730,45 @@ class ImagePut { extension := "png" pStream := this.put_stream(pBitmap, extension, quality) - DllCall("ole32\GetHGlobalFromStream", "ptr", pStream, "uint*", hData:=0) - pData := DllCall("GlobalLock", "ptr", hData, "ptr") - nSize := DllCall("GlobalSize", "uint", pData, "uptr") - - ; Using CryptBinaryToStringA saves about 2MB in memory. - DllCall("Crypt32.dll\CryptBinaryToStringA", "ptr", pData, "uint", nSize, "uint", 0x4000000C, "ptr", 0, "uint*", length:=0) - VarSetCapacity(hex, length, 0) - DllCall("Crypt32.dll\CryptBinaryToStringA", "ptr", pData, "uint", nSize, "uint", 0x4000000C, "ptr", &hex, "uint*", length) - - DllCall("GlobalUnlock", "ptr", hData) + hex := this.set_hex(pStream) ObjRelease(pStream) + return hex + } - return StrGet(&hex, length, "CP0") + set_hex(pStream) { + return this.set_string(pStream, 0x4000000C) ; CRYPT_STRING_NOCRLF | CRYPT_STRING_HEXRAW } put_base64(pBitmap, extension := "", quality := "") { - ; Thanks noname - https://www.autohotkey.com/boards/viewtopic.php?style=7&p=144247#p144247 - ; Default extension is PNG for small sizes! if !(extension ~= "^(?i:bmp|dib|rle|jpg|jpeg|jpe|jfif|gif|tif|tiff|png)$") extension := "png" pStream := this.put_stream(pBitmap, extension, quality) - DllCall("ole32\GetHGlobalFromStream", "ptr", pStream, "uint*", hData:=0) - pData := DllCall("GlobalLock", "ptr", hData, "ptr") - nSize := DllCall("GlobalSize", "uint", pData, "uptr") + base64 := this.set_base64(pStream) + ObjRelease(pStream) + return base64 + } - ; Using CryptBinaryToStringA saves about 2MB in memory. - DllCall("Crypt32.dll\CryptBinaryToStringA", "ptr", pData, "uint", nSize, "uint", 0x40000001, "ptr", 0, "uint*", length:=0) - VarSetCapacity(base64, length, 0) - DllCall("Crypt32.dll\CryptBinaryToStringA", "ptr", pData, "uint", nSize, "uint", 0x40000001, "ptr", &base64, "uint*", length) + set_base64(pStream) { + return this.set_string(pStream, 0x40000001) ; CRYPT_STRING_NOCRLF | CRYPT_STRING_BASE64 + } - DllCall("GlobalUnlock", "ptr", hData) - ObjRelease(pStream) + set_string(pStream, flags) { + ; Thanks noname - https://www.autohotkey.com/boards/viewtopic.php?style=7&p=144247#p144247 + + ; For compatibility with SHCreateMemStream do not use GetHGlobalFromStream. + DllCall("shlwapi\IStream_Size", "ptr", pStream, "ptr*", size:=0, "uint") + VarSetCapacity(bin, size) + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") + DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", &bin, "uint", size, "uint") + + ; Using CryptBinaryToStringA saves about 2MB in memory. + DllCall("crypt32\CryptBinaryToStringA", "ptr", &bin, "uint", size, "uint", flags, "ptr", 0, "uint*", length:=0) + VarSetCapacity(str, length) + DllCall("crypt32\CryptBinaryToStringA", "ptr", &bin, "uint", size, "uint", flags, "ptr", &str, "uint*", length) - return StrGet(&base64, length, "CP0") + return StrGet(&str, length, "CP0") } select_codec(pBitmap, extension, quality, ByRef pCodec, ByRef ep, ByRef ci, ByRef v) { @@ -1696,22 +1786,91 @@ class ImagePut { throw Exception("Could not find a matching encoder for the specified file format.") ; JPEG default quality is 75. Otherwise set a quality value from [0-100]. - if quality ~= "^-?\d+$" && ("image/jpeg" = StrGet(NumGet(ci, idx+32+4*A_PtrSize, "ptr"), "UTF-16")) { ; MimeType + if (quality ~= "^-?\d+$") and ("image/jpeg" = StrGet(NumGet(ci, idx+32+4*A_PtrSize, "ptr"), "UTF-16")) { ; MimeType ; Use a separate buffer to store the quality as ValueTypeLong (4). - VarSetCapacity(v, 4, 0), NumPut(quality, v, "uint") + VarSetCapacity(v, 4), NumPut(quality, v, "uint") ; struct EncoderParameter - http://www.jose.it-berater.org/gdiplus/reference/structures/encoderparameter.htm ; enum ValueType - https://docs.microsoft.com/en-us/dotnet/api/system.drawing.imaging.encoderparametervaluetype ; clsid Image Encoder Constants - http://www.jose.it-berater.org/gdiplus/reference/constants/gdipimageencoderconstants.htm VarSetCapacity(ep, 24+2*A_PtrSize) ; sizeof(EncoderParameter) = ptr + n*(28, 32) NumPut( 1, ep, 0, "uptr") ; Count - DllCall("ole32\CLSIDFromString", "wstr", "{1D5BE4B5-FA4A-452D-9CDD-5DB35105E7EB}", "ptr", &ep+A_PtrSize) + DllCall("ole32\CLSIDFromString", "wstr", "{1D5BE4B5-FA4A-452D-9CDD-5DB35105E7EB}", "ptr", &ep+A_PtrSize, "uint") NumPut( 1, ep, 16+A_PtrSize, "uint") ; Number of Values NumPut( 4, ep, 20+A_PtrSize, "uint") ; Type NumPut( &v, ep, 24+A_PtrSize, "ptr") ; Value } } + select_extension(pStream, ByRef extension) { + VarSetCapacity(signature, 12) + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") + DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", &signature, "uint", 12, "uint") + + ; This function sniffs the first 12 bytes and matches a known file signature. + ; 256 bytes is recommended, but images only need 12 bytes. + ; See: https://en.wikipedia.org/wiki/List_of_file_signatures + DllCall("urlmon\FindMimeFromData" + , "ptr", 0 ; pBC + , "ptr", 0 ; pwzUrl + , "ptr", &signature ; pBuffer + , "uint", 12 ; cbSize + , "ptr", 0 ; pwzMimeProposed + , "uint", 0x20 ; dwMimeFlags + , "ptr*", MimeType:=0 ; ppwzMimeOut + , "uint", 0 ; dwReserved + , "uint") + + ; The output is a pointer to a Mime string. It must be dereferenced. + MimeType := StrGet(MimeType, "UTF-16") + + if (MimeType ~= "gif") + extension := "gif" + if (MimeType ~= "jpeg") + extension := "jpg" + if (MimeType ~= "png") + extension := "png" + if (MimeType ~= "tiff") + extension := "tif" + if (MimeType ~= "bmp") + extension := "bmp" + } + + select_filepath(ByRef filepath, ByRef default, pStream := "") { + ; Remove whitespace. Seperate the filepath. Adjust for directories. + filepath := Trim(filepath) + SplitPath filepath,, directory, extension, filename + if InStr(FileExist(filepath), "D") + directory .= "\" filename, filename := "" + if (directory != "" && !InStr(FileExist(directory), "D")) + FileCreateDir % directory + directory := (directory != "") ? directory : "." + + ; Validate filepath, defaulting to PNG. https://stackoverflow.com/a/6804755 + if !(extension ~= "^(?i:bmp|dib|rle|jpg|jpeg|jpe|jfif|gif|tif|tiff|png)$") { + if (extension != "") + filename .= "." extension + + extension := default + + if (pStream) { + this.select_extension(pStream, extension) + } + } + filename := RegExReplace(filename, "S)(?i:^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$|[<>:|?*\x00-\x1F\x22\/\\])") + if (filename == "") { + FormatTime, filename,, % "yyyy-MM-dd HH?mm?ss" + filepath := directory "\" filename "." extension + if FileExist(filepath) { ; Check for collisions. + loop + filepath := directory "\" filename " (" A_Index ")." extension + until !FileExist(filepath) + } + } + else + filepath := directory "\" filename "." extension + } + ; All references to gdiplus and pToken must be absolute! static gdiplus := 0, pToken := 0 @@ -1775,53 +1934,80 @@ ImageEqual(images*) { class ImageEqual extends ImagePut { call(images*) { - if (images.Count() == 0) + ; Returns false is there are no images to be compared. + if (images.length() == 0) return false - if (images.Count() == 1) - return true - this.gdiplusStartup() - ; Convert the images to pBitmaps (byte arrays). + ; Set the first image to its own variable to allow passing by reference. + image := images[1] + + ; Allow the ImageType exception to bubble up. + try type := this.DontVerifyImageType(image) + catch + type := this.ImageType(image) + + ; Convert only the first image to a bitmap. + if !(pBitmap1 := this.ToBitmap(type, image)) + throw Exception("The image cannot be converted into a bitmap. The pointer value is zero.") + + ; If there is only one image, verify that image. + if (images.length() == 1) { + if DllCall("gdiplus\GdipCloneImage", "ptr", pBitmap1, "ptr*", pBitmapClone:=0) + throw Exception("Validation failed. Unable to access and clone the bitmap.") + + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmapClone) + Goto Good_Ending + } + + ; If there are multiple images, do not convert the first image. for i, image in images { - try type := this.DontVerifyImageType(image) - catch - try type := this.ImageType(image) - catch { ; Not a valid image. - result := false - break - } - - if (A_Index == 1) { - pBitmap1 := this.toBitmap(type, image) - } else { - pBitmap2 := this.toBitmap(type, image) - result := this.isBitmapEqual(pBitmap1, pBitmap2) + if (A_Index != 1) { + + ; Guess the type of the image. + try type := this.DontVerifyImageType(image) + catch + type := this.ImageType(image) + + ; Convert the other image to a bitmap. + pBitmap2 := this.ToBitmap(type, image) + + ; Compare the two images. + if !this.BitmapEqual(pBitmap1, pBitmap2) + Goto Bad_Ending ; Exit the loop if the comparison failed. + + ; Cleanup the bitmap. DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap2) - if (result) - continue - else { - result := false - break - } } } + Good_Ending: ; After getting isekai'ed you somehow build a prosperous kingdom and rule the land. DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap1) - this.gdiplusShutdown() + return true - return result + Bad_Ending: ; Turns out your best friend became super jealous of you and killed you in your sleep. + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap2) + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap1) + this.gdiplusShutdown() + return false } - isBitmapEqual(pBitmap1, pBitmap2, Format := 0x26200A) { - ; Make sure both bitmaps are valid pointers. - if (!pBitmap1 || !pBitmap2) - return false + BitmapEqual(sBitmap1, sBitmap2, Format := 0x26200A) { + ; Make sure both source bitmaps are valid pointers. + if (!sBitmap1 || !sBitmap2) + throw Exception("The pointer has a value of zero.") + + ; Create clones of the supplied source bitmaps. + if DllCall("gdiplus\GdipCloneImage", "ptr", sBitmap1, "ptr*", pBitmap1:=0) + throw Exception("Bitmap 1 is not a valid bitmap.") + + if DllCall("gdiplus\GdipCloneImage", "ptr", sBitmap2, "ptr*", pBitmap2:=0) + throw Exception("Bitmap 2 is not a valid bitmap.") - ; Check if pointers are identical. - if (pBitmap1 == pBitmap2) + ; Check if source bitmap pointers are identical. + if (sBitmap1 == sBitmap2) return true ; The two bitmaps must be the same size. @@ -1830,6 +2016,10 @@ class ImageEqual extends ImagePut { DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap1, "uint*", height1:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap2, "uint*", height2:=0) + ; Dimensions must be non-zero. + if (!width1 || !width2 || !height1 || !height2) + throw Exception("The size of the bitmap is zero.") + ; Match bitmap dimensions. if (width1 != width2 || height1 != height2) return false @@ -1876,6 +2066,10 @@ class ImageEqual extends ImagePut { DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap1, "ptr", &BitmapData1) DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap2, "ptr", &BitmapData2) + ; Cleanup bitmap clones. + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap1) + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap2) + ; Compare stopped byte. return (byte == size) ? true : false } From 81779fd3df46649c1ebaf74e45a85dc58b57ae47 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 3 Oct 2021 19:17:57 -0400 Subject: [PATCH 036/492] Allow pStream to be freed while leaving the hData intact --- ImagePut (for v1).ahk | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 29783b51..e1b0bc68 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -703,9 +703,12 @@ class ImagePut { if DllCall("IsClipboardFormatAvailable", "uint", png, "int") { if !(hData := DllCall("GetClipboardData", "uint", png, "ptr")) throw Exception("Shared clipboard data has been deleted.") - DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", true, "ptr*", pStream:=0, "uint") + + ; Allow the stream to be freed while leaving the hData intact. + ; Please read: https://devblogs.microsoft.com/oldnewthing/20210930-00/?p=105745 + DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", false, "ptr*", pStream:=0, "uint") DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", pBitmap:=0) - ; DO NOT RELEASE THE STREAM. CLIPBOARD IS SHARED MEMORY IF YOU RELEASE IT WILL BE DELETED. + ObjRelease(pStream) } ; Fallback to CF_BITMAP. This format does not support transparency even with put_hBitmap(). From 2030c94d64aded19c716666e16cecc3b2d42863c Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 3 Oct 2021 19:30:46 -0400 Subject: [PATCH 037/492] Create an HGlobal whose stream can be freed --- ImagePut (for v1).ahk | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index e1b0bc68..16ecf727 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1238,11 +1238,21 @@ class ImagePut { ; #1 - Place the image onto the clipboard as a PNG stream. ; Thanks Jochen Arndt - https://www.codeproject.com/Answers/1207927/Saving-an-image-to-the-clipboard#answer3 - pStream := this.put_stream(pBitmap, "png") + + ; Create a Stream whose underlying HGlobal must be referenced or lost forever. + ; Please read: https://devblogs.microsoft.com/oldnewthing/20210929-00/?p=105742 + DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "int", false, "ptr*", pStream:=0, "uint") + this.select_codec(pBitmap, "png",, pCodec, ep, ci, v) + DllCall("gdiplus\GdipSaveImageToStream", "ptr", pBitmap, "ptr", pStream, "ptr", pCodec, "ptr", (ep) ? &ep : 0) + + ; Rescue the HGlobal after GDI+ has written the PNG to stream and release the stream. DllCall("ole32\GetHGlobalFromStream", "ptr", pStream, "uint*", hData:=0, "uint") + ObjRelease(pStream) + + ; Set the rescued HGlobal to the clipboard as a shared object. png := DllCall("RegisterClipboardFormat", "str", "png", "uint") ; case insensitive DllCall("SetClipboardData", "uint", png, "ptr", hData) - ; DO NOT RELEASE THE STREAM. CLIPBOARD IS SHARED MEMORY IF YOU RELEASE IT WILL BE DELETED. + ; #2 - Place the image onto the clipboard in the CF_DIB format using a bottom-up bitmap. ; Thanks tic - https://www.autohotkey.com/boards/viewtopic.php?t=6517 From e85630c74ed4ecb8aad61de9a4c789b0bebbf53c Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 3 Oct 2021 19:49:23 -0400 Subject: [PATCH 038/492] "int" return types are unnecessary --- ImagePut (for v1).ahk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 16ecf727..d25013fa 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -700,7 +700,7 @@ class ImagePut { ; Prefer the PNG stream if available because of transparency support. png := DllCall("RegisterClipboardFormat", "str", "png", "uint") - if DllCall("IsClipboardFormatAvailable", "uint", png, "int") { + if DllCall("IsClipboardFormatAvailable", "uint", png) { if !(hData := DllCall("GetClipboardData", "uint", png, "ptr")) throw Exception("Shared clipboard data has been deleted.") @@ -712,7 +712,7 @@ class ImagePut { } ; Fallback to CF_BITMAP. This format does not support transparency even with put_hBitmap(). - else if DllCall("IsClipboardFormatAvailable", "uint", 2, "int") { + else if DllCall("IsClipboardFormatAvailable", "uint", 2) { if !(hBitmap := DllCall("GetClipboardData", "uint", 2, "ptr")) throw Exception("Shared clipboard data has been deleted.") DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "ptr", hBitmap, "ptr", 0, "ptr*", pBitmap:=0) From d4c87790f2a0737136b1705d125ecd2cfec30dec Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 3 Oct 2021 20:02:35 -0400 Subject: [PATCH 039/492] organize NumGet --- ImagePut (for v1).ahk | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index d25013fa..e3e24955 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1262,19 +1262,17 @@ class ImagePut { ; struct BITMAP - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmap VarSetCapacity(dib, size := 64+5*A_PtrSize) ; sizeof(DIBSECTION) = 84, 104 DllCall("GetObject", "ptr", hBitmap, "int", size, "ptr", &dib) - - ; Find the pointer to the bitmap bits and the size of the bitmap bits. - pBits := NumGet(dib, A_PtrSize = 4 ? 20:24, "ptr") ; bmBits - size := NumGet(dib, A_PtrSize = 4 ? 44:52, "uint") ; biSizeImage + , pBits := NumGet(dib, A_PtrSize = 4 ? 20:24, "ptr") ; bmBits + , size := NumGet(dib, A_PtrSize = 4 ? 44:52, "uint") ; biSizeImage ; Allocate space for a new device independent bitmap on movable memory. hdib := DllCall("GlobalAlloc", "uint", 0x2, "uptr", 40 + size, "ptr") ; sizeof(BITMAPINFOHEADER) = 40 pdib := DllCall("GlobalLock", "ptr", hdib, "ptr") - ; Copy the BITMAPINFOHEADER from the old DIB to the new DIB. + ; Copy the BITMAPINFOHEADER. DllCall("RtlMoveMemory", "ptr", pdib, "ptr", &dib + (A_PtrSize = 4 ? 24:32), "uptr", 40) - ; Copy the pixel data from the old DIB to the new DIB. + ; Copy the pixel data. DllCall("RtlMoveMemory", "ptr", pdib+40, "ptr", pBits, "uptr", size) ; Unlock to moveable memory because the clipboard requires it. @@ -1414,21 +1412,20 @@ class ImagePut { WS_EX_TRANSPARENT := 0x20 WS_EX_DLGMODALFRAME := 0x1 + style := WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_CLIPCHILDREN | WS_POPUP | WS_CLIPSIBLINGS ;| WS_SIZEBOX + styleEx := WS_EX_TOPMOST | WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME ;| WS_EX_LAYERED ;| WS_EX_STATICEDGE + VarSetCapacity(rect, 16) NumPut(Floor((A_ScreenWidth - width) / 2), rect, 0, "int") NumPut(Floor((A_ScreenHeight - height) / 2), rect, 4, "int") NumPut(Floor((A_ScreenWidth + width) / 2), rect, 8, "int") NumPut(Floor((A_ScreenHeight + height) / 2), rect, 12, "int") - style := WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_CLIPCHILDREN | WS_POPUP | WS_CLIPSIBLINGS ;| WS_SIZEBOX - styleEx := WS_EX_TOPMOST | WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME ;| WS_EX_LAYERED ;| WS_EX_STATICEDGE - DllCall("AdjustWindowRectEx", "ptr", &rect, "uint", style, "uint", 0, "uint", styleEx) - - x := NumGet(rect, 0, "int") - y := NumGet(rect, 4, "int") - w := NumGet(rect, 8, "int") - NumGet(rect, 0, "int") - h := NumGet(rect, 12, "int") - NumGet(rect, 4, "int") + , x := NumGet(rect, 0, "int") + , y := NumGet(rect, 4, "int") + , w := NumGet(rect, 8, "int") - NumGet(rect, 0, "int") + , h := NumGet(rect, 12, "int") - NumGet(rect, 4, "int") hwnd0 := DllCall("CreateWindowEx" , "uint", styleEx From f74dab05336ff6657ab8b5dc9aa55fc3e4382b93 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 5 Oct 2021 23:38:51 -0400 Subject: [PATCH 040/492] comments, strings, and names --- ImagePut (for v1).ahk | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index e3e24955..e07bd9ea 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -133,6 +133,8 @@ class ImagePut { && crop[3] ~= "^-?\d+(\.\d*)?%?$" && crop[4] ~= "^-?\d+(\.\d*)?%?$" _scale := scale != 1 && scale ~= "^\d+(\.\d+)?$" + + ; Check if a stream can be used as an intermediate. if not this.ForceDecodeImagePixels and not _crop and not _scale and (type ~= "^(?i:url|file|stream|RandomAccessStream|hex|base64)$") and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64)$") { @@ -150,6 +152,8 @@ class ImagePut { return coimage } + + ; Fallback to GDI+ bitmap as the intermediate. else { ; Make a copy of the image as a pBitmap. pBitmap := this.ToBitmap(type, image) @@ -184,6 +188,7 @@ class ImagePut { DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) } + ; Check for dangling pointers. this.gdiplusShutdown(cotype) return coimage @@ -371,7 +376,6 @@ class ImagePut { try if ComObjQuery(image, "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}") return "RandomAccessStream", ObjRelease(image) } - ; A "hex" string is binary image data encoded into text using hexadecimal. if (StrLen(image) >= 116) && (image ~= "(?i)^\s*(0x)?[0-9a-f]+\s*$") return "hex" @@ -381,6 +385,7 @@ class ImagePut { . "(?:[A-Za-z0-9+\/]{4})*+(?:[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{2}==)?\s*$") return "base64" + ; For more helpful error messages: Catch file names without extensions! for extension in ["bmp","dib","rle","jpg","jpeg","jpe","jfif","gif","tif","tiff","png","ico","exe","dll"] if FileExist(image "." extension) @@ -563,7 +568,7 @@ class ImagePut { if (cotype = "base64") return this.set_base64(pStream) - throw Exception("Conversion from bitmap to " cotype " is not supported.") + throw Exception("Conversion from stream to " cotype " is not supported.") } DisposeImage(pBitmap) { @@ -706,7 +711,7 @@ class ImagePut { ; Allow the stream to be freed while leaving the hData intact. ; Please read: https://devblogs.microsoft.com/oldnewthing/20210930-00/?p=105745 - DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", false, "ptr*", pStream:=0, "uint") + DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", false, "ptr*", pStream:=0, "uint") DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", pBitmap:=0) ObjRelease(pStream) } @@ -719,10 +724,7 @@ class ImagePut { DllCall("DeleteObject", "ptr", hBitmap) } - ; Close the clipboard. - if !DllCall("CloseClipboard") - throw Exception("Clipboard could not be closed.") - + DllCall("CloseClipboard") return pBitmap } @@ -1285,8 +1287,7 @@ class ImagePut { DllCall("SetClipboardData", "uint", 8, "ptr", hdib) ; Close the clipboard. - if !DllCall("CloseClipboard") - throw Exception("Clipboard could not be closed.") + DllCall("CloseClipboard") return "" } @@ -1856,8 +1857,9 @@ class ImagePut { FileCreateDir % directory directory := (directory != "") ? directory : "." - ; Validate filepath, defaulting to PNG. https://stackoverflow.com/a/6804755 + ; Validate filepath. https://stackoverflow.com/a/6804755 if !(extension ~= "^(?i:bmp|dib|rle|jpg|jpeg|jpe|jfif|gif|tif|tiff|png)$") { + ; If the extension does not match a known file type, append it to the filename. if (extension != "") filename .= "." extension @@ -1960,7 +1962,7 @@ class ImageEqual extends ImagePut { ; Convert only the first image to a bitmap. if !(pBitmap1 := this.ToBitmap(type, image)) - throw Exception("The image cannot be converted into a bitmap. The pointer value is zero.") + throw Exception("Conversion to bitmap failed. The pointer value is zero.") ; If there is only one image, verify that image. if (images.length() == 1) { @@ -2004,20 +2006,20 @@ class ImageEqual extends ImagePut { return false } - BitmapEqual(sBitmap1, sBitmap2, Format := 0x26200A) { + BitmapEqual(SourceBitmap1, SourceBitmap2, Format := 0x26200A) { ; Make sure both source bitmaps are valid pointers. - if (!sBitmap1 || !sBitmap2) - throw Exception("The pointer has a value of zero.") + if (!SourceBitmap1 || !SourceBitmap2) + throw Exception("The bitmap pointer cannot be a value of zero.") ; Create clones of the supplied source bitmaps. - if DllCall("gdiplus\GdipCloneImage", "ptr", sBitmap1, "ptr*", pBitmap1:=0) - throw Exception("Bitmap 1 is not a valid bitmap.") + if DllCall("gdiplus\GdipCloneImage", "ptr", SourceBitmap1, "ptr*", pBitmap1:=0) + throw Exception("Cloning Bitmap1 failed.") - if DllCall("gdiplus\GdipCloneImage", "ptr", sBitmap2, "ptr*", pBitmap2:=0) - throw Exception("Bitmap 2 is not a valid bitmap.") + if DllCall("gdiplus\GdipCloneImage", "ptr", SourceBitmap2, "ptr*", pBitmap2:=0) + throw Exception("Cloning Bitmap2 failed.") ; Check if source bitmap pointers are identical. - if (sBitmap1 == sBitmap2) + if (SourceBitmap1 == SourceBitmap2) return true ; The two bitmaps must be the same size. @@ -2028,7 +2030,7 @@ class ImageEqual extends ImagePut { ; Dimensions must be non-zero. if (!width1 || !width2 || !height1 || !height2) - throw Exception("The size of the bitmap is zero.") + throw Exception("The bitmap dimensions cannot be zero.") ; Match bitmap dimensions. if (width1 != width2 || height1 != height2) From e8b34516f8156ea09b6a18bd626238dad6b198a1 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 6 Oct 2021 00:09:11 -0400 Subject: [PATCH 041/492] Extension was not being returned by select_filepath --- ImagePut (for v1).ahk | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index e07bd9ea..e51b4755 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1611,8 +1611,8 @@ class ImagePut { put_file(pBitmap, filepath := "", quality := "") { ; Thanks tic - https://www.autohotkey.com/boards/viewtopic.php?t=6517 - default := "png" - this.select_filepath(filepath, default) + extension := "png" + this.select_filepath(filepath, extension) ; Select the proper codec based on the extension of the file. this.select_codec(pBitmap, extension, quality, pCodec, ep, ci, v) @@ -1630,8 +1630,8 @@ class ImagePut { } set_file(pStream, filepath := "") { - default := "png" - this.select_filepath(filepath, default, pStream) + extension := "png" + this.select_filepath(filepath, extension, pStream) ; For compatibility with SHCreateMemStream do not use GetHGlobalFromStream. DllCall("shlwapi\SHCreateStreamOnFileEx" @@ -1847,7 +1847,10 @@ class ImagePut { extension := "bmp" } - select_filepath(ByRef filepath, ByRef default, pStream := "") { + select_filepath(ByRef filepath, ByRef extension, pStream := "") { + ; Save extension as default. + default := extension + ; Remove whitespace. Seperate the filepath. Adjust for directories. filepath := Trim(filepath) SplitPath filepath,, directory, extension, filename From 4a6c81cf62feb1d9f26348563d4e8cba7292dabd Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 6 Oct 2021 00:17:18 -0400 Subject: [PATCH 042/492] CodecInfo now throws instead of defaulting to PNG --- ImagePut (for v1).ahk | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index e51b4755..012df914 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1788,13 +1788,15 @@ class ImagePut { DllCall("gdiplus\GdipGetImageEncoders", "uint", count, "uint", size, "ptr", &ci := VarSetCapacity(ci, size)) ; struct ImageCodecInfo - http://www.jose.it-berater.org/gdiplus/reference/structures/imagecodecinfo.htm - loop % count + loop { + if (A_Index > count) + throw Exception("Could not find a matching encoder for the specified file format.") + idx := (48+7*A_PtrSize)*(A_Index-1) - until InStr(StrGet(NumGet(ci, idx+32+3*A_PtrSize, "ptr"), "UTF-16"), "*." extension) ; FilenameExtension + } until InStr(StrGet(NumGet(ci, idx+32+3*A_PtrSize, "ptr"), "UTF-16"), "*." extension) ; FilenameExtension ; Get the pointer to the clsid of the matching encoder. - if !(pCodec := &ci + idx) ; ClassID - throw Exception("Could not find a matching encoder for the specified file format.") + pCodec := &ci + idx ; ClassID ; JPEG default quality is 75. Otherwise set a quality value from [0-100]. if (quality ~= "^-?\d+$") and ("image/jpeg" = StrGet(NumGet(ci, idx+32+4*A_PtrSize, "ptr"), "UTF-16")) { ; MimeType From e0c8b7dbbf3fdf0f72094f6a7c396e4b70915707 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 6 Oct 2021 10:23:48 -0400 Subject: [PATCH 043/492] Use (0, 0) as the origin for put_screenshot --- ImagePut (for v1).ahk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 012df914..4609fbcd 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1305,8 +1305,8 @@ class ImagePut { DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) - x := (IsObject(screenshot) && screenshot[1] != "") ? screenshot[1] : Round((A_ScreenWidth - width) / 2) - y := (IsObject(screenshot) && screenshot[2] != "") ? screenshot[2] : Round((A_ScreenHeight - height) / 2) + x := (IsObject(screenshot) && screenshot[1] != "") ? screenshot[1] : 0 + y := (IsObject(screenshot) && screenshot[2] != "") ? screenshot[2] : 0 w := (IsObject(screenshot) && screenshot[3] != "") ? screenshot[3] : width h := (IsObject(screenshot) && screenshot[4] != "") ? screenshot[4] : height From 815d2ba6d71b5949d5c5eb395172fba73922ce39 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 6 Oct 2021 10:50:11 -0400 Subject: [PATCH 044/492] Use HALFTONE for StretchBlt --- ImagePut (for v1).ahk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 4609fbcd..4f7ce30f 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1318,6 +1318,9 @@ class ImagePut { ; Retrieve the device context for the screen. ddc := DllCall("GetDC", "ptr", 0, "ptr") + ; Perform bilinear interpolation. See: https://stackoverflow.com/a/4358798 + DllCall("SetStretchBltMode", "ptr", ddc, "int", 4) ; HALFTONE + ; Copies a portion of the screen to a new device context. DllCall("gdi32\StretchBlt" , "ptr", ddc, "int", x, "int", y, "int", w, "int", h From 29e3efb4b20e19335017382cded64c162ab23fb1 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 7 Oct 2021 10:52:48 -0400 Subject: [PATCH 045/492] Add missing parameter in select_codec --- ImagePut (for v1).ahk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 4f7ce30f..feb6ce79 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1244,7 +1244,7 @@ class ImagePut { ; Create a Stream whose underlying HGlobal must be referenced or lost forever. ; Please read: https://devblogs.microsoft.com/oldnewthing/20210929-00/?p=105742 DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "int", false, "ptr*", pStream:=0, "uint") - this.select_codec(pBitmap, "png",, pCodec, ep, ci, v) + this.select_codec(pBitmap, "png", "", pCodec, ep, ci, v) DllCall("gdiplus\GdipSaveImageToStream", "ptr", pBitmap, "ptr", pStream, "ptr", pCodec, "ptr", (ep) ? &ep : 0) ; Rescue the HGlobal after GDI+ has written the PNG to stream and release the stream. From 8b62b49b74485883441027dddd58a979c6548b5a Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 7 Oct 2021 17:55:15 -0400 Subject: [PATCH 046/492] PixelFormat has size of int --- ImagePut (for v1).ahk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index feb6ce79..17ad8550 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -579,7 +579,7 @@ class ImagePut { ; Get Bitmap width, height, and format. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) - DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", pBitmap, "uint*", format:=0) + DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", pBitmap, "int*", format:=0) ; Are the numbers percentages? crop[3] := (crop[3] ~= "%$") ? SubStr(crop[3], 1, -1) * 0.01 * width : crop[3] @@ -625,7 +625,7 @@ class ImagePut { ; Get Bitmap width, height, and format. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) - DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", pBitmap, "uint*", format:=0) + DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", pBitmap, "int*", format:=0) safe_w := Ceil(width * scale) safe_h := Ceil(height * scale) From cbf61425fb8bf98c0fe3804e67ff82d3ab3b9511 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 7 Oct 2021 18:51:28 -0400 Subject: [PATCH 047/492] ImageEqual refactored and CloneImage now keeps PixelFormat --- ImagePut (for v1).ahk | 112 +++++++++++++++++++++++++----------------- 1 file changed, 68 insertions(+), 44 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 17ad8550..61660546 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1104,7 +1104,18 @@ class ImagePut { } from_bitmap(image) { - DllCall("gdiplus\GdipCloneImage", "ptr", image, "ptr*", pBitmap:=0) + ; Retain the current PixelFormat, unlike GdipCloneImage. + DllCall("gdiplus\GdipGetImageWidth", "ptr", image, "uint*", width:=0) + DllCall("gdiplus\GdipGetImageHeight", "ptr", image, "uint*", height:=0) + DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", image, "int*", format:=0) + DllCall("gdiplus\GdipCloneBitmapAreaI" + , "int", 0 + , "int", 0 + , "int", width + , "int", height + , "int", format + , "ptr", image + , "ptr*", pBitmap:=0) return pBitmap } @@ -1972,7 +1983,7 @@ class ImageEqual extends ImagePut { if !(pBitmap1 := this.ToBitmap(type, image)) throw Exception("Conversion to bitmap failed. The pointer value is zero.") - ; If there is only one image, verify that image. + ; If there is only one image, verify that image and return. if (images.length() == 1) { if DllCall("gdiplus\GdipCloneImage", "ptr", pBitmap1, "ptr*", pBitmapClone:=0) throw Exception("Validation failed. Unable to access and clone the bitmap.") @@ -1981,7 +1992,7 @@ class ImageEqual extends ImagePut { Goto Good_Ending } - ; If there are multiple images, do not convert the first image. + ; If there are multiple images, compare each subsequent image to the first. for i, image in images { if (A_Index != 1) { @@ -2014,69 +2025,82 @@ class ImageEqual extends ImagePut { return false } - BitmapEqual(SourceBitmap1, SourceBitmap2, Format := 0x26200A) { - ; Make sure both source bitmaps are valid pointers. - if (!SourceBitmap1 || !SourceBitmap2) - throw Exception("The bitmap pointer cannot be a value of zero.") - - ; Create clones of the supplied source bitmaps. - if DllCall("gdiplus\GdipCloneImage", "ptr", SourceBitmap1, "ptr*", pBitmap1:=0) - throw Exception("Cloning Bitmap1 failed.") + BitmapEqual(SourceBitmap1, SourceBitmap2, PixelFormat := 0x26200A) { + ; Make sure both source bitmaps are valid GDI+ pointers. This will throw if not... + DllCall("gdiplus\GdipGetImageType", "ptr", SourceBitmap1, "ptr*", type1:=0) + DllCall("gdiplus\GdipGetImageType", "ptr", SourceBitmap2, "ptr*", type2:=0) - if DllCall("gdiplus\GdipCloneImage", "ptr", SourceBitmap2, "ptr*", pBitmap2:=0) - throw Exception("Cloning Bitmap2 failed.") + ; ImageTypeUnknown = 0, ImageTypeBitmap = 1, and ImageTypeMetafile = 2. + if (type1 != 1 || type2 != 1) + throw Exception("The GDI+ pointer is not a bitmap.") ; Check if source bitmap pointers are identical. if (SourceBitmap1 == SourceBitmap2) return true ; The two bitmaps must be the same size. - DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap1, "uint*", width1:=0) - DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap2, "uint*", width2:=0) - DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap1, "uint*", height1:=0) - DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap2, "uint*", height2:=0) + DllCall("gdiplus\GdipGetImageWidth", "ptr", SourceBitmap1, "uint*", width1:=0) + DllCall("gdiplus\GdipGetImageWidth", "ptr", SourceBitmap2, "uint*", width2:=0) + DllCall("gdiplus\GdipGetImageHeight", "ptr", SourceBitmap1, "uint*", height1:=0) + DllCall("gdiplus\GdipGetImageHeight", "ptr", SourceBitmap2, "uint*", height2:=0) + DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", SourceBitmap1, "int*", format1:=0) + DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", SourceBitmap2, "int*", format2:=0) ; Dimensions must be non-zero. - if (!width1 || !width2 || !height1 || !height2) + if !(width1 && width2 && height1 && height2) throw Exception("The bitmap dimensions cannot be zero.") ; Match bitmap dimensions. if (width1 != width2 || height1 != height2) return false - ; struct RECT - https://docs.microsoft.com/en-us/windows/win32/api/windef/ns-windef-rect - VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 - NumPut( width1, Rect, 8, "uint") ; Width - NumPut( height1, Rect, 12, "uint") ; Height + ; Create clones of the supplied source bitmaps in their original PixelFormat. + ; This has the side effect of (1) removing negative stride and solves + ; the problem when (2) both bitmaps reference the same stream and only + ; one of them is able to retrieve the pixel data through LockBits. + ; I assume that instead of locking the stream, the clones lock the originals. + + pBitmap1 := pBitmap2 := 0 + Loop 2 + if DllCall("gdiplus\GdipCloneBitmapAreaI" + , "int", 0 + , "int", 0 + , "int", width%A_Index% + , "int", height%A_Index% + , "int", format%A_Index% + , "ptr", SourceBitmap%A_Index% + , "ptr*", pBitmap%A_Index%:=0) + throw Exception("Cloning Bitmap" A_Index " failed.") - ; Do this twice. - while ((i++:=i?i:0) < 2) { ; for(int i = 1; i <= 2; i++) + ; struct RECT - https://docs.microsoft.com/en-us/windows/win32/api/windef/ns-windef-rect + VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 + NumPut( width1, Rect, 8, "uint") ; Width + NumPut( height1, Rect, 12, "uint") ; Height - ; Create a BitmapData structure. - VarSetCapacity(BitmapData%i%, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + ; Create a BitmapData structure. + VarSetCapacity(BitmapData1, 16+2*A_PtrSize) ; sizeof(BitmapData) = 24, 32 + VarSetCapacity(BitmapData2, 16+2*A_PtrSize) ; sizeof(BitmapData) = 24, 32 - ; Transfer the pixels to a read-only buffer. Avoid using a different PixelFormat. + ; Transfer the pixels to a read-only buffer. The user can declare a PixelFormat. + Loop 2 DllCall("gdiplus\GdipBitmapLockBits" - , "ptr", pBitmap%i% + , "ptr", pBitmap%A_Index% , "ptr", &Rect , "uint", 1 ; ImageLockMode.ReadOnly - , "int", Format ; Format32bppArgb is fast. - , "ptr", &BitmapData%i%) - - ; Get Stride (number of bytes per horizontal line). - stride%i% := NumGet(BitmapData%i%, 8, "int") - - ; If the Stride is negative, clone the image to make it top-down; redo the loop. - if (stride%i% < 0) { - DllCall("gdiplus\GdipCloneImage", "ptr", pBitmap%i%, "ptr*", pBitmapClone:=0) - DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap%i%) ; Permanently deletes. - pBitmap%i% := pBitmapClone - i-- ; "Let's go around again! Ha!" https://bit.ly/2AWWcM3 - } + , "int", PixelFormat ; Format32bppArgb is fast. + , "ptr", &BitmapData%A_Index%) - ; Get Scan0 (top-left pixel at 0,0). - Scan0%i% := NumGet(BitmapData%i%, 16, "ptr") - } + ; Get Stride (number of bytes per horizontal line). + stride1 := NumGet(BitmapData1, 8, "int") + stride2 := NumGet(BitmapData2, 8, "int") + + ; Well the image has already been cloned, so the stride should never be negative. + if (stride1 < 0 || stride2 < 0) ; See: https://stackoverflow.com/a/10341340 + throw Exception("Negative stride. Please report this error to the developer.") + + ; Get Scan0 (top-left pixel at 0,0). + Scan01 := NumGet(BitmapData1, 16, "ptr") + Scan02 := NumGet(BitmapData2, 16, "ptr") ; RtlCompareMemory preforms an unsafe comparison stopping at the first different byte. size := stride1 * height1 From 0ecf0eb7a2846cfaada8691236eb164429998eb4 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 7 Oct 2021 19:05:31 -0400 Subject: [PATCH 048/492] v2 catchup --- ImagePut.ahk | 912 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 575 insertions(+), 337 deletions(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index d951b712..98399de4 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -4,100 +4,100 @@ ; Date: 2021-09-28 ; Version: v1.1 -#Requires AutoHotkey v2-a134+ +#Requires AutoHotkey v2.0-beta.1+ ; Puts the image into a file format and returns a base64 encoded string. ; extension - File Encoding | string -> bmp, gif, jpg, png, tiff ; quality - JPEG Quality Level | integer -> 0 - 100 -ImagePutBase64(image, extension := "", quality := "") - => ImagePut("base64", image,,, extension, quality) - +ImagePutBase64(image, extension := "", quality := "") { + return ImagePut("base64", image,,, extension, quality) +} ; Puts the image into a GDI+ Bitmap and returns a pointer. -ImagePutBitmap(image) - => ImagePut("bitmap", image) - +ImagePutBitmap(image) { + return ImagePut("bitmap", image) +} ; Puts the image into a GDI+ Bitmap and returns a buffer object with GDI+ scope. -ImagePutBuffer(image) - => ImagePut("buffer", image) - +ImagePutBuffer(image) { + return ImagePut("buffer", image) +} ; Puts the image onto the clipboard and returns ClipboardAll(). -ImagePutClipboard(image) - => ImagePut("clipboard", image) - +ImagePutClipboard(image) { + return ImagePut("clipboard", image) +} ; Puts the image as the cursor and returns the variable A_Cursor. ; xHotspot - X Click Point | pixel -> 0 - width ; yHotspot - Y Click Point | pixel -> 0 - height -ImagePutCursor(image, xHotspot := "", yHotspot := "") - => ImagePut("cursor", image,,, xHotspot, yHotspot) - +ImagePutCursor(image, xHotspot := "", yHotspot := "") { + return ImagePut("cursor", image,,, xHotspot, yHotspot) +} ; Puts the image behind the desktop icons and returns the string "desktop". ; scale - Scale Factor | real -> A_ScreenHeight / height. -ImagePutDesktop(image, scale := 1) - => ImagePut("desktop", image,, scale) - +ImagePutDesktop(image, scale := 1) { + return ImagePut("desktop", image,, scale) +} ; Puts the image into a file and returns a relative filepath. ; filepath - Filepath + Extension | string -> *.bmp, *.gif, *.jpg, *.png, *.tiff ; quality - JPEG Quality Level | integer -> 0 - 100 -ImagePutFile(image, filepath := "", quality := "") - => ImagePut("file", image,,, filepath, quality) - +ImagePutFile(image, filepath := "", quality := "") { + return ImagePut("file", image,,, filepath, quality) +} ; Puts the image into a device independent bitmap and returns the handle. ; alpha - Alpha Replacement Color | RGB -> 0xFFFFFF -ImagePutHBitmap(image, alpha := "") - => ImagePut("hBitmap", image,,, alpha) - +ImagePutHBitmap(image, alpha := "") { + return ImagePut("hBitmap", image,,, alpha) +} ; Puts the image into a file format and returns a hexadecimal encoded string. ; extension - File Encoding | string -> bmp, gif, jpg, png, tiff ; quality - JPEG Quality Level | integer -> 0 - 100 -ImagePutHex(image, extension := "", quality := "") - => ImagePut("hex", image,,, extension, quality) - +ImagePutHex(image, extension := "", quality := "") { + return ImagePut("hex", image,,, extension, quality) +} ; Puts the image into an icon and returns the handle. -ImagePutHIcon(image) - => ImagePut("hBitmap", image) - +ImagePutHIcon(image) { + return ImagePut("hBitmap", image) +} ; Puts the image into a file format and returns a pointer to a RandomAccessStream. ; extension - File Encoding | string -> bmp, gif, jpg, png, tiff ; quality - JPEG Quality Level | integer -> 0 - 100 -ImagePutRandomAccessStream(image, extension := "", quality := "") - => ImagePut("RandomAccessStream", image,,, extension, quality) - +ImagePutRandomAccessStream(image, extension := "", quality := "") { + return ImagePut("RandomAccessStream", image,,, extension, quality) +} ; Puts the image on the shared screen device context and returns an array of coordinates. ; screenshot - Screen Coordinates | array -> [x,y,w,h] or [0,0] ; alpha - Alpha Replacement Color | RGB -> 0xFFFFFF -ImagePutScreenshot(image, screenshot := "", alpha := "") - => ImagePut("screenshot", image,,, screenshot, alpha) - +ImagePutScreenshot(image, screenshot := "", alpha := "") { + return ImagePut("screenshot", image,,, screenshot, alpha) +} ; Puts the image into a file format and returns a pointer to a stream. ; extension - File Encoding | string -> bmp, gif, jpg, png, tiff ; quality - JPEG Quality Level | integer -> 0 - 100 -ImagePutStream(image, extension := "", quality := "") - => ImagePut("stream", image,,, extension, quality) - +ImagePutStream(image, extension := "", quality := "") { + return ImagePut("stream", image,,, extension, quality) +} ; Puts the image as the desktop wallpaper and returns the string "wallpaper". -ImagePutWallpaper(image) - => ImagePut("wallpaper", image) - +ImagePutWallpaper(image) { + return ImagePut("wallpaper", image) +} ; Puts the image in a window and returns a handle to a window. ; title - Window Caption Title | string -> MyTitle -ImagePutWindow(image, title := "") - => ImagePut("window", image,,, title) - +ImagePutWindow(image, title := "") { + return ImagePut("window", image,,, title) +} @@ -106,18 +106,24 @@ ImagePutWindow(image, title := "") class ImagePut { + ; If true the conversion will always go through a GDI+ Bitmap and the original file encoding will be lost. + static ForceDecodeImagePixels := false + + ; If true the pBitmap will always be filled with image data instead of referencing it and copying when needed. + static ForcePushImageToMemory := false + ; ImagePut() - Puts an image from anywhere to anywhere. ; cotype - Output Type | string -> Case Insensitive. Read documentation. ; image - Input Image | image -> Anything. Refer to ImageType(). ; crop - Crop Coordinates | array -> [x,y,w,h] could be negative or percent. ; scale - Scale Factor | real -> 2.0 - ; terms* - Additional Parameters | variadic -> Extra parameters found in toCotype(). + ; terms* - Additional Parameters | variadic -> Extra parameters found in BitmapToCoimage(). static call(cotype, image, crop := "", scale := "", terms*) { this.gdiplusStartup() ; Take a guess as to what the image might be. (>90% accuracy!) - try type := this.DontVerifyImageType(image) + try type := this.DontVerifyImageType(&image) catch type := this.ImageType(image) @@ -127,36 +133,68 @@ class ImagePut { && crop[3] ~= "^-?\d+(\.\d*)?%?$" && crop[4] ~= "^-?\d+(\.\d*)?%?$" _scale := scale != 1 && scale ~= "^\d+(\.\d+)?$" - ; Make a copy of the image as a pBitmap. - pBitmap := this.toBitmap(type, image) - ; Crop the image. - if (_crop) { - pBitmap2 := this.BitmapCrop(pBitmap, crop) - DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) - pBitmap := pBitmap2 - } + ; Check if a stream can be used as an intermediate. + if not this.ForceDecodeImagePixels and not _crop and not _scale + and (type ~= "^(?i:url|file|stream|RandomAccessStream|hex|base64)$") + and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64)$") { + + ; Convert to a stream intermediate then to the output coimage. + pStream := this.ToStream(type, image) + coimage := this.StreamToCoimage(cotype, pStream, terms*) + + ; Prevents the stream object from being freed. + if (cotype = "stream") + ObjAddRef(pStream) - ; Scale the image. - if (_scale) { - pBitmap2 := this.BitmapScale(pBitmap, scale) - DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) - pBitmap := pBitmap2 + ; Free the temporary stream object. + ObjRelease(pStream) + + return coimage } - ; Put the pBitmap to wherever the cotype specifies. - coimage := this.toCotype(cotype, pBitmap, terms*) + ; Fallback to GDI+ bitmap as the intermediate. + else { + ; Make a copy of the image as a pBitmap. + pBitmap := this.ToBitmap(type, image) + + ; Load the image pixels to the bitmap buffer. + ; This increases memory usage but prevents any changes to the pixels, + ; and bypasses any copy-on-write and copy on LockBits read behavior. + ; This must be called immediately after the pBitmap is created + ; or it will fail without throwing any errors. + if (this.ForcePushImageToMemory) + DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmap) + + ; Crop the image. + if (_crop) { + pBitmap2 := this.BitmapCrop(pBitmap, crop) + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + pBitmap := pBitmap2 + } + + ; Scale the image. + if (_scale) { + pBitmap2 := this.BitmapScale(pBitmap, scale) + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + pBitmap := pBitmap2 + } + + ; Put the pBitmap to wherever the cotype specifies. + coimage := this.BitmapToCoimage(cotype, pBitmap, terms*) - ; Clean up the pBitmap copy. Export raw pointers if requested. - if !(cotype = "bitmap" || cotype = "buffer") - DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + ; Clean up the pBitmap copy. Export raw pointers if requested. + if !(cotype = "bitmap" || cotype = "buffer") + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + } + ; Check for dangling pointers. this.gdiplusShutdown(cotype) return coimage } - static DontVerifyImageType(image) { + static DontVerifyImageType(&image) { if !IsObject(image) throw Error("Must be an object.") @@ -328,7 +366,7 @@ class ImagePut { ; Note 1: All GDI+ functions add 1 to the reference count of COM objects. ; Note 2: GDI+ pBitmaps that are queried cease to stay pBitmaps. - ObjRelease(image) + ObjRelease(image) ; Therefore do not move this, it has been tested. ; A "stream" is a pointer to the IStream interface. try if ComObjQuery(image, "{0000000C-0000-0000-C000-000000000046}") @@ -356,7 +394,7 @@ class ImagePut { throw Error("Image type could not be identified.") } - static toBitmap(type, image) { + static ToBitmap(type, image) { if (type = "clipboard") return this.from_clipboard() @@ -415,75 +453,122 @@ class ImagePut { if (type = "sprite") return this.from_sprite(image) - throw Error("Conversion from type " type " is not supported.") + throw Error("Conversion from " type " to bitmap is not supported.") } - static toCotype(cotype, pBitmap, term1 := "", term2 := "", *) { - ; toCotype("clipboard", pBitmap) + static BitmapToCoimage(cotype, pBitmap, p1 := "", p2 := "", p*) { + ; BitmapToCoimage("clipboard", pBitmap) if (cotype = "clipboard") return this.put_clipboard(pBitmap) - ; toCotype("buffer", pBitmap) + ; BitmapToCoimage("buffer", pBitmap) if (cotype = "buffer") return this.put_buffer(pBitmap) - ; toCotype("screenshot", pBitmap, screenshot, alpha) + ; BitmapToCoimage("screenshot", pBitmap, screenshot, alpha) if (cotype = "screenshot") - return this.put_screenshot(pBitmap, term1, term2) + return this.put_screenshot(pBitmap, p1, p2) - ; toCotype("window", pBitmap, title) + ; BitmapToCoimage("window", pBitmap, title) if (cotype = "window") - return this.put_window(pBitmap, term1) + return this.put_window(pBitmap, p1) - ; toCotype("desktop", pBitmap) + ; BitmapToCoimage("desktop", pBitmap) if (cotype = "desktop") return this.put_desktop(pBitmap) - ; toCotype("wallpaper", pBitmap) + ; BitmapToCoimage("wallpaper", pBitmap) if (cotype = "wallpaper") return this.put_wallpaper(pBitmap) - ; toCotype("cursor", pBitmap, xHotspot, yHotspot) + ; BitmapToCoimage("cursor", pBitmap, xHotspot, yHotspot) if (cotype = "cursor") - return this.put_cursor(pBitmap, term1, term2) + return this.put_cursor(pBitmap, p1, p2) - ; toCotype("url", pBitmap) + ; BitmapToCoimage("url", pBitmap) if (cotype = "url") return this.put_url(pBitmap) - ; toCotype("file", pBitmap, filename, quality) + ; BitmapToCoimage("file", pBitmap, filepath, quality) if (cotype = "file") - return this.put_file(pBitmap, term1, term2) + return this.put_file(pBitmap, p1, p2) - ; toCotype("hBitmap", pBitmap, alpha) + ; BitmapToCoimage("hBitmap", pBitmap, alpha) if (cotype = "hBitmap") - return this.put_hBitmap(pBitmap, term1) + return this.put_hBitmap(pBitmap, p1) - ; toCotype("hIcon", pBitmap) + ; BitmapToCoimage("hIcon", pBitmap) if (cotype = "hIcon") return this.put_hIcon(pBitmap) - ; toCotype("bitmap", pBitmap) + ; BitmapToCoimage("bitmap", pBitmap) if (cotype = "bitmap") return pBitmap - ; toCotype("stream", pBitmap, extension, quality) + ; BitmapToCoimage("stream", pBitmap, extension, quality) if (cotype = "stream") - return this.put_stream(pBitmap, term1, term2) + return this.put_stream(pBitmap, p1, p2) - ; toCotype("RandomAccessStream", pBitmap, extension, quality) + ; BitmapToCoimage("RandomAccessStream", pBitmap, extension, quality) if (cotype = "RandomAccessStream") - return this.put_RandomAccessStream(pBitmap, term1, term2) + return this.put_RandomAccessStream(pBitmap, p1, p2) - ; toCotype("hex", pBitmap, extension, quality) + ; BitmapToCoimage("hex", pBitmap, extension, quality) if (cotype = "hex") - return this.put_hex(pBitmap, term1, term2) + return this.put_hex(pBitmap, p1, p2) - ; toCotype("base64", pBitmap, extension, quality) + ; BitmapToCoimage("base64", pBitmap, extension, quality) if (cotype = "base64") - return this.put_base64(pBitmap, term1, term2) + return this.put_base64(pBitmap, p1, p2) - throw Error("Conversion to type " cotype " is not supported.") + throw Error("Conversion from bitmap to " cotype " is not supported.") + } + + static ToStream(type, image) { + + if (type = "url") + return this.get_url(image) + + if (type = "file") + return this.get_file(image) + + if (type = "stream") + return this.get_stream(image) + + if (type = "RandomAccessStream") + return this.get_RandomAccessStream(image) + + if (type = "hex") + return this.get_hex(image) + + if (type = "base64") + return this.get_base64(image) + + throw Error("Conversion from " type " to stream is not supported.") + } + + static StreamToCoimage(cotype, pStream, p1 := "", p2 := "", p*) { + ; StreamToCoimage("file", pStream, filepath) + if (cotype = "file") + return this.set_file(pStream, p1) + + ; StreamToCoimage("stream", pStream) + if (cotype = "stream") + return pStream + + ; StreamToCoimage("RandomAccessStream", pStream) + if (cotype = "RandomAccessStream") + return this.set_RandomAccessStream(pStream) + + ; StreamToCoimage("hex", pStream) + if (cotype = "hex") + return this.set_hex(pStream) + + ; StreamToCoimage("base64", pStream) + if (cotype = "base64") + return this.set_base64(pStream) + + throw Error("Conversion from stream to " cotype " is not supported.") } static DisposeImage(pBitmap) { @@ -611,25 +696,30 @@ class ImagePut { static from_clipboard() { ; Open the clipboard with exponential backoff. loop - if DllCall("OpenClipboard", "ptr", 0) + if DllCall("OpenClipboard", "ptr", A_ScriptHwnd) break else if A_Index < 6 Sleep (2**(A_Index-1) * 30) else throw Error("Clipboard could not be opened.") - ; Prefer the PNG stream if available considering it supports transparency. + ; Prefer the PNG stream if available because of transparency support. png := DllCall("RegisterClipboardFormat", "str", "png", "uint") - if DllCall("IsClipboardFormatAvailable", "uint", png, "int") { - hData := DllCall("GetClipboardData", "uint", png, "ptr") - DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", true, "ptr*", &pStream:=0) + if DllCall("IsClipboardFormatAvailable", "uint", png) { + if !(hData := DllCall("GetClipboardData", "uint", png, "ptr")) + throw Error("Shared clipboard data has been deleted.") + + ; Allow the stream to be freed while leaving the hData intact. + ; Please read: https://devblogs.microsoft.com/oldnewthing/20210930-00/?p=105745 + DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", false, "ptr*", &pStream:=0, "HRESULT") DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", &pBitmap:=0) ObjRelease(pStream) } ; Fallback to CF_BITMAP. This format does not support transparency even with put_hBitmap(). - else if DllCall("IsClipboardFormatAvailable", "uint", 2, "int") { - hBitmap := DllCall("GetClipboardData", "uint", 2, "ptr") + else if DllCall("IsClipboardFormatAvailable", "uint", 2) { + if !(hBitmap := DllCall("GetClipboardData", "uint", 2, "ptr")) + throw Error("Shared clipboard data has been deleted.") DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "ptr", hBitmap, "ptr", 0, "ptr*", &pBitmap:=0) DllCall("DeleteObject", "ptr", hBitmap) } @@ -829,13 +919,18 @@ class ImagePut { } static from_url(image) { + pStream := this.get_url(image) + DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", &pBitmap:=0) + pStream := "" + return pBitmap + } + + static get_url(image) { req := ComObject("WinHttp.WinHttpRequest.5.1") req.Open("GET", image) req.Send() - IStream := ComObjQuery(req.ResponseStream, "{0000000C-0000-0000-C000-000000000046}") - DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", IStream, "ptr*", &pBitmap:=0) - IStream := "" - return pBitmap + IStream := ComObjQuery(req.ResponseStream, "{0000000C-0000-0000-C000-000000000046}"), ObjAddRef(IStream.ptr) + return IStream.ptr } static from_file(image) { @@ -843,6 +938,17 @@ class ImagePut { return pBitmap } + static get_file(image) { + file := FileOpen(image, "r") + hData := DllCall("GlobalAlloc", "uint", 0x2, "uptr", file.length, "ptr") + pData := DllCall("GlobalLock", "ptr", hData, "ptr") + file.RawRead(pData, file.length) + DllCall("GlobalUnlock", "ptr", hData) + file.Close() + DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", true, "ptr*", &pStream:=0, "HRESULT") + return pStream + } + static from_monitor(image) { if (image > 0) { MonitorGet(image, &Left, &Top, &Right, &Bottom) @@ -932,7 +1038,7 @@ class ImagePut { static from_hIcon(image) { ; struct ICONINFO - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-iconinfo - ii := Buffer(8+3*A_PtrSize, 0) ; sizeof(ICONINFO) = 20, 32 + ii := Buffer(8+3*A_PtrSize) ; sizeof(ICONINFO) = 20, 32 DllCall("GetIconInfo", "ptr", image, "ptr", ii) ; xHotspot := NumGet(ii, 4, "uint") ; yHotspot := NumGet(ii, 8, "uint") @@ -998,7 +1104,18 @@ class ImagePut { } static from_bitmap(image) { - DllCall("gdiplus\GdipCloneImage", "ptr", image, "ptr*", &pBitmap:=0) + ; Retain the current PixelFormat, unlike GdipCloneImage. + DllCall("gdiplus\GdipGetImageWidth", "ptr", image, "uint*", &width:=0) + DllCall("gdiplus\GdipGetImageHeight", "ptr", image, "uint*", &height:=0) + DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", image, "int*", &format:=0) + DllCall("gdiplus\GdipCloneBitmapAreaI" + , "int", 0 + , "int", 0 + , "int", width + , "int", height + , "int", format + , "ptr", image + , "ptr*", &pBitmap:=0) return pBitmap } @@ -1007,62 +1124,69 @@ class ImagePut { return pBitmap } + static get_stream(image) { + ; Creates a new, separate stream. Necessary to separate reference counting through a clone. + ComCall(IStream_Clone := 13, image, "ptr*", &pStream:=0) + return pStream + } + static from_RandomAccessStream(image) { - ; Get the Class ID from a GUID string. - CLSID := Buffer(16, 0) - if result := DllCall("ole32\CLSIDFromString", "wstr", "{0000000C-0000-0000-C000-000000000046}", "ptr", CLSID, "uint") - throw Error("CLSIDFromString failed. Error: " . Format("{:#x}", result)) + ; Creating a Bitmap from stream adds +3 to the reference count until DisposeImage is called. + pStream := this.get_RandomAccessStream(image) + DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", &pBitmap:=0) + ObjRelease(pStream) + return pBitmap + } - ; Convert RandomAccessStream to stream. - DllCall("ShCore\CreateStreamOverRandomAccessStream", "ptr", image, "ptr", CLSID, "ptr*", &pStream:=0, "uint") + static get_RandomAccessStream(image) { + ; Note that the returned stream shares a reference count with the original RandomAccessStream. + CLSID := Buffer(16) + DllCall("ole32\CLSIDFromString", "wstr", "{0000000C-0000-0000-C000-000000000046}", "ptr", CLSID, "HRESULT") + DllCall("ShCore\CreateStreamOverRandomAccessStream", "ptr", image, "ptr", CLSID, "ptr*", &pStream:=0, "HRESULT") + return pStream + } - ; Read stream to pBitmap. + static from_hex(image) { + pStream := this.get_hex(image) DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", &pBitmap:=0) - - ; Manually free the pointer to an IStream. ObjRelease(pStream) - return pBitmap } - static from_hex(image) { - ; Trim whitespace and remove header. + static get_hex(image) { image := Trim(image) image := RegExReplace(image, "^(0[xX])") + return this.get_string(image, 0xC) ; CRYPT_STRING_HEXRAW + } - ; Converts the image to binary data by first asking for the size. - DllCall("crypt32\CryptStringToBinary" - , "ptr", StrPtr(image), "uint", 0, "uint", 0xC, "ptr", 0, "uint*", &size:=0, "ptr", 0, "ptr", 0) - bin := Buffer(size, 0) - DllCall("crypt32\CryptStringToBinary" - , "ptr", StrPtr(image), "uint", 0, "uint", 0xC, "ptr", bin, "uint*", size, "ptr", 0, "ptr", 0) - - ; Makes a stream for conversion into a pBitmap. - pStream := DllCall("shlwapi\SHCreateMemStream", "ptr", bin, "uint", size, "ptr") + static from_base64(image) { + pStream := this.get_base64(image) DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", &pBitmap:=0) ObjRelease(pStream) - return pBitmap } - static from_base64(image) { - ; Trim whitespace and remove header. + static get_base64(image) { image := Trim(image) image := RegExReplace(image, "^data:image\/[a-z]+;base64,") + return this.get_string(image, 0x1) ; CRYPT_STRING_BASE64 + } - ; Converts the image to binary data by first asking for the size. + static get_string(image, flags) { + ; Ask for the size. Then allocate movable memory, copy to the buffer, unlock, and create stream. DllCall("crypt32\CryptStringToBinary" - , "ptr", StrPtr(image), "uint", 0, "uint", 0x1, "ptr", 0, "uint*", &size:=0, "ptr", 0, "ptr", 0) - bin := Buffer(size, 0) + , "ptr", StrPtr(image), "uint", 0, "uint", flags, "ptr", 0, "uint*", &size:=0, "ptr", 0, "ptr", 0) + + hData := DllCall("GlobalAlloc", "uint", 0x2, "uptr", size, "ptr") + pData := DllCall("GlobalLock", "ptr", hData, "ptr") + DllCall("crypt32\CryptStringToBinary" - , "ptr", StrPtr(image), "uint", 0, "uint", 0x1, "ptr", bin, "uint*", size, "ptr", 0, "ptr", 0) + , "ptr", StrPtr(image), "uint", 0, "uint", flags, "ptr", pData, "uint*", size, "ptr", 0, "ptr", 0) - ; Makes a stream for conversion into a pBitmap. - pStream := DllCall("shlwapi\SHCreateMemStream", "ptr", bin, "uint", size, "ptr") - DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", &pBitmap:=0) - ObjRelease(pStream) + DllCall("GlobalUnlock", "ptr", hData) + DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", true, "ptr*", &pStream:=0, "HRESULT") - return pBitmap + return pStream } static from_sprite(image) { @@ -1115,71 +1239,62 @@ class ImagePut { ; Open the clipboard with exponential backoff. loop - if DllCall("OpenClipboard", "ptr", 0) + if DllCall("OpenClipboard", "ptr", A_ScriptHwnd) break else if A_Index < 6 Sleep (2**(A_Index-1) * 30) else throw Error("Clipboard could not be opened.") - ; Clear the clipboard. + ; If not opened with a valid window handle EmptyClipboard will crash the next call to OpenClipboard. DllCall("EmptyClipboard") ; #1 - Place the image onto the clipboard as a PNG stream. ; Thanks Jochen Arndt - https://www.codeproject.com/Answers/1207927/Saving-an-image-to-the-clipboard#answer3 - pStream := this.put_stream(pBitmap, "png") - DllCall("ole32\GetHGlobalFromStream", "ptr", pStream, "uint*", &hData:=0) - DllCall("SetClipboardData", "uint", DllCall("RegisterClipboardFormat", "str", "png", "uint"), "ptr", hData) + + ; Create a Stream whose underlying HGlobal must be referenced or lost forever. + ; Please read: https://devblogs.microsoft.com/oldnewthing/20210929-00/?p=105742 + DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "int", false, "ptr*", &pStream:=0, "HRESULT") + this.select_codec(pBitmap, "png", "", &pCodec, &ep, &ci, &v) + DllCall("gdiplus\GdipSaveImageToStream", "ptr", pBitmap, "ptr", pStream, "ptr", pCodec, "ptr", IsSet(ep) ? ep : 0) + + ; Rescue the HGlobal after GDI+ has written the PNG to stream and release the stream. + DllCall("ole32\GetHGlobalFromStream", "ptr", pStream, "uint*", &hData:=0, "HRESULT") ObjRelease(pStream) - ; #2 - Place the image onto the clipboard in the CF_DIB format in ARGB using 3 color masks. (Extra 12 byte offset.) - ; Thanks Nyerguds - https://stackoverflow.com/a/46424800 + ; Set the rescued HGlobal to the clipboard as a shared object. + png := DllCall("RegisterClipboardFormat", "str", "png", "uint") ; case insensitive + DllCall("SetClipboardData", "uint", png, "ptr", hData) - ; Get Bitmap width, height, and format. - DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) - DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) - DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", pBitmap, "uint*", &format:=0) - ; Get Bitmap bits per pixel, stride, and size. - bpp := (format & 0x00FF00) >> 8 - stride := (bpp >> 3) * width - size := stride * height + ; #2 - Place the image onto the clipboard in the CF_DIB format using a bottom-up bitmap. + ; Thanks tic - https://www.autohotkey.com/boards/viewtopic.php?t=6517 + DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", "ptr", pBitmap, "ptr*", &hBitmap:=0, "uint", 0) ; struct DIBSECTION - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-dibsection - ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader - hdib := DllCall("GlobalAlloc", "uint", 0x42, "uptr", 40 + 12 + size, "ptr") + ; struct BITMAP - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmap + dib := Buffer(64+5*A_PtrSize) ; sizeof(DIBSECTION) = 84, 104 + DllCall("GetObject", "ptr", hBitmap, "int", dib.size, "ptr", dib) + , pBits := NumGet(dib, A_PtrSize = 4 ? 20:24, "ptr") ; bmBits + , size := NumGet(dib, A_PtrSize = 4 ? 44:52, "uint") ; biSizeImage + + ; Allocate space for a new device independent bitmap on movable memory. + hdib := DllCall("GlobalAlloc", "uint", 0x2, "uptr", 40 + size, "ptr") ; sizeof(BITMAPINFOHEADER) = 40 pdib := DllCall("GlobalLock", "ptr", hdib, "ptr") - NumPut( "uint", 40, pdib, 0) ; Size - NumPut( "int", width, pdib, 4) ; Width - NumPut( "int", -height, pdib, 8) ; Height - Negative so (0, 0) is top-left. - NumPut("ushort", 1, pdib, 12) ; Planes - NumPut("ushort", bpp, pdib, 14) ; BitCount / BitsPerPixel - NumPut( "uint", 0x3, pdib, 16) ; Compression - NumPut( "uint", size, pdib, 20) ; SizeImage (bytes) - ; The following bitfields when masked extract the respective color channels. - NumPut( "uint", 0x00FF0000, pdib, 40) ; Red - NumPut( "uint", 0x0000FF00, pdib, 44) ; Green - NumPut( "uint", 0x000000FF, pdib, 48) ; Blue - - ; Transfer data from source pBitmap to the global memory manually. - Rect := Buffer(16, 0) ; sizeof(Rect) = 16 - NumPut( "uint", width, Rect, 8) ; Width - NumPut( "uint", height, Rect, 12) ; Height - BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 - NumPut( "int", stride, BitmapData, 8) ; Stride - NumPut( "ptr", pdib + 52, BitmapData, 16) ; Scan0 - DllCall("gdiplus\GdipBitmapLockBits" - , "ptr", pBitmap - , "ptr", Rect - , "uint", 5 ; ImageLockMode.UserInputBuffer | ImageLockMode.ReadOnly - , "int", 0x26200A ; Format32bppArgb - , "ptr", BitmapData) ; Contains the pointer (pdib) to the hData. - DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", BitmapData) - ; Unlock the memory as it is complete. + ; Copy the BITMAPINFOHEADER. + DllCall("RtlMoveMemory", "ptr", pdib, "ptr", dib.ptr + (A_PtrSize = 4 ? 24:32), "uptr", 40) + + ; Copy the pixel data. + DllCall("RtlMoveMemory", "ptr", pdib+40, "ptr", pBits, "uptr", size) + + ; Unlock to moveable memory because the clipboard requires it. DllCall("GlobalUnlock", "ptr", hdib) - ; Add CF_DIB as a format to the clipboard. + ; Delete the temporary hBitmap. + DllCall("DeleteObject", "ptr", hBitmap) + + ; CF_DIB (8) can be synthesized into CF_BITMAP (2), CF_PALETTE (9), and CF_DIBV5 (17). DllCall("SetClipboardData", "uint", 8, "ptr", hdib) ; Close the clipboard. @@ -1201,8 +1316,8 @@ class ImagePut { DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) - x := (IsObject(screenshot) && screenshot[1] != "") ? screenshot[1] : Round((A_ScreenWidth - width) / 2) - y := (IsObject(screenshot) && screenshot[2] != "") ? screenshot[2] : Round((A_ScreenHeight - height) / 2) + x := (IsObject(screenshot) && screenshot[1] != "") ? screenshot[1] : 0 + y := (IsObject(screenshot) && screenshot[2] != "") ? screenshot[2] : 0 w := (IsObject(screenshot) && screenshot[3] != "") ? screenshot[3] : width h := (IsObject(screenshot) && screenshot[4] != "") ? screenshot[4] : height @@ -1214,6 +1329,9 @@ class ImagePut { ; Retrieve the device context for the screen. ddc := DllCall("GetDC", "ptr", 0, "ptr") + ; Perform bilinear interpolation. See: https://stackoverflow.com/a/4358798 + DllCall("SetStretchBltMode", "ptr", ddc, "int", 4) ; HALFTONE + ; Copies a portion of the screen to a new device context. DllCall("gdi32\StretchBlt" , "ptr", ddc, "int", x, "int", y, "int", w, "int", h @@ -1274,7 +1392,7 @@ class ImagePut { ; struct tagWNDCLASSEXA - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexa ; struct tagWNDCLASSEXW - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexw _ := (A_PtrSize = 4) - wc := Buffer(_ ? 48:80, 0) ; sizeof(WNDCLASSEX) = 48, 80 + wc := Buffer(_ ? 48:80) ; sizeof(WNDCLASSEX) = 48, 80 NumPut( "uint", wc.size, wc, 0) ; cbSize NumPut( "uint", 0, wc, 4) ; style NumPut( "ptr", pWndProc, wc, 8) ; lpfnWndProc @@ -1309,21 +1427,20 @@ class ImagePut { WS_EX_TRANSPARENT := 0x20 WS_EX_DLGMODALFRAME := 0x1 - rect := Buffer(16, 0) + style := WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_CLIPCHILDREN | WS_POPUP | WS_CLIPSIBLINGS ;| WS_SIZEBOX + styleEx := WS_EX_TOPMOST | WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME ;| WS_EX_LAYERED ;| WS_EX_STATICEDGE + + rect := Buffer(16) NumPut("int", Floor((A_ScreenWidth - width) / 2), rect, 0) NumPut("int", Floor((A_ScreenHeight - height) / 2), rect, 4) NumPut("int", Floor((A_ScreenWidth + width) / 2), rect, 8) NumPut("int", Floor((A_ScreenHeight + height) / 2), rect, 12) - style := WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_CLIPCHILDREN | WS_POPUP | WS_CLIPSIBLINGS ;| WS_SIZEBOX - styleEx := WS_EX_TOPMOST | WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME ;| WS_EX_LAYERED ;| WS_EX_STATICEDGE - DllCall("AdjustWindowRectEx", "ptr", rect, "uint", style, "uint", 0, "uint", styleEx) - - x := NumGet(rect, 0, "int") - y := NumGet(rect, 4, "int") - w := NumGet(rect, 8, "int") - NumGet(rect, 0, "int") - h := NumGet(rect, 12, "int") - NumGet(rect, 4, "int") + , x := NumGet(rect, 0, "int") + , y := NumGet(rect, 4, "int") + , w := NumGet(rect, 8, "int") - NumGet(rect, 0, "int") + , h := NumGet(rect, 12, "int") - NumGet(rect, 4, "int") hwnd0 := DllCall("CreateWindowEx" , "uint", styleEx @@ -1460,7 +1577,7 @@ class ImagePut { else throw Error("Unable to create temporary image file.") ; Set the temporary image file as the new desktop wallpaper. - DllCall("SystemParametersInfo", "uint", 20, "uint", 0, "str", buf, "uint", 2) + DllCall("SystemParametersInfo", "uint", SPI_SETDESKWALLPAPER := 20, "uint", 0, "str", buf, "uint", 2) ; This is a delayed delete call. #Persistent may be required on v1. DeleteFile := DllCall.Bind("DeleteFile", "str", filepath) @@ -1478,7 +1595,7 @@ class ImagePut { ; Sets the hotspot of the cursor by changing the icon into a cursor. if (xHotspot != "" || yHotspot != "") { ; struct ICONINFO - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-iconinfo - ii := Buffer(8+3*A_PtrSize, 0) ; sizeof(ICONINFO) = 20, 32 + ii := Buffer(8+3*A_PtrSize) ; sizeof(ICONINFO) = 20, 32 DllCall("GetIconInfo", "ptr", hIcon, "ptr", ii) ; Fill the ICONINFO structure. NumPut("uint", false, ii, 0) ; true/false are icon/cursor respectively. (xHotspot != "") ? NumPut("uint", xHotspot, ii, 4) : "" ; Set the xHotspot value. (Default: center point) @@ -1508,34 +1625,8 @@ class ImagePut { static put_file(pBitmap, filepath := "", quality := "") { ; Thanks tic - https://www.autohotkey.com/boards/viewtopic.php?t=6517 - - ; Remove whitespace. Seperate the filepath. Adjust for directories. - filepath := Trim(filepath) - SplitPath filepath,, &directory, &extension, &filename - if DirExist(filepath) - directory .= "\" filename, filename := "" - if (directory != "" && !DirExist(directory)) - DirCreate(directory) - directory := (directory != "") ? directory : "." - - ; Validate filepath, defaulting to PNG. https://stackoverflow.com/a/6804755 - if !(extension ~= "^(?i:bmp|dib|rle|jpg|jpeg|jpe|jfif|gif|tif|tiff|png)$") { - if (extension != "") - filename .= "." extension - extension := "png" - } - filename := RegExReplace(filename, "S)(?i:^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$|[<>:|?*\x00-\x1F\x22\/\\])") - if (filename == "") { - filename := FormatTime(, "yyyy-MM-dd HH?mm?ss") - filepath := directory "\" filename "." extension - if FileExist(filepath) { ; Check for collisions. - loop - filepath := directory "\" filename " (" A_Index ")." extension - until !FileExist(filepath) - } - } - else - filepath := directory "\" filename "." extension + extension := "png" + this.select_filepath(&filepath, &extension) ; Select the proper codec based on the extension of the file. this.select_codec(pBitmap, extension, quality, &pCodec, &ep, &ci, &v) @@ -1552,6 +1643,27 @@ class ImagePut { return filepath } + static set_file(pStream, filepath := "") { + extension := "png" + this.select_filepath(&filepath, &extension, pStream) + + ; For compatibility with SHCreateMemStream do not use GetHGlobalFromStream. + DllCall("shlwapi\SHCreateStreamOnFileEx" + , "wstr", filepath + , "uint", 0x1001 ; STGM_CREATE | STGM_WRITE + , "uint", 0x80 ; FILE_ATTRIBUTE_NORMAL + , "int", true ; fCreate is ignored when STGM_CREATE is set. + , "ptr", 0 ; pstmTemplate (reserved) + , "ptr*", &pFileStream:=0 + ,"HRESULT") + DllCall("shlwapi\IStream_Size", "ptr", pStream, "ptr*", &size:=0, "HRESULT") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") + DllCall("shlwapi\IStream_Copy", "ptr", pStream, "ptr", pFileStream, "uint", size, "HRESULT") + ObjRelease(pFileStream) + + return filepath + } + static put_hBitmap(pBitmap, alpha := "") { ; Revert to built in functionality if a replacement color is declared. if (alpha != "") { ; This built-in version is about 25% slower. @@ -1611,29 +1723,29 @@ class ImagePut { this.select_codec(pBitmap, extension, quality, &pCodec, &ep, &ci, &v) ; Create a Stream. - DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "int", true, "ptr*", &pStream:=0) + DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "int", true, "ptr*", &pStream:=0, "HRESULT") DllCall("gdiplus\GdipSaveImageToStream", "ptr", pBitmap, "ptr", pStream, "ptr", pCodec, "ptr", IsSet(ep) ? ep : 0) return pStream } static put_RandomAccessStream(pBitmap, extension := "", quality := "") { - ; Thanks teadrinker - https://www.autohotkey.com/boards/viewtopic.php?f=6&t=72674 - - ; Which is faster, bmp or png? pStream := this.put_stream(pBitmap, extension, quality) + pRandomAccessStream := this.set_RandomAccessStream(pStream) + ObjRelease(pStream) ; Decrement the reference count of the IStream interface. + return pRandomAccessStream + } - ; Get the Class ID from a GUID string. - CLSID := Buffer(16, 0) - if result := DllCall("ole32\CLSIDFromString", "wstr", "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}", "ptr", CLSID, "uint") - throw Error("CLSIDFromString failed. Error: " . Format("{:#x}", result)) - - ; Create a RandomAccessStream - DllCall("ShCore\CreateRandomAccessStreamOverStream", "ptr", pStream, "uint", 1, "ptr", CLSID, "ptr*", &pRandomAccessStream:=0, "uint") - - ; The handle to the stream object is automatically freed when the stream object is released. - ObjRelease(pStream) - + static set_RandomAccessStream(pStream) { + ; Thanks teadrinker - https://www.autohotkey.com/boards/viewtopic.php?f=6&t=72674 + CLSID := Buffer(16) + DllCall("ole32\CLSIDFromString", "wstr", "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}", "ptr", CLSID, "HRESULT") + DllCall("ShCore\CreateRandomAccessStreamOverStream" + , "ptr", pStream + , "uint", BSOS_PREFERDESTINATIONSTREAM := 1 + , "ptr", CLSID + , "ptr*", &pRandomAccessStream:=0 + ,"HRESULT") return pRandomAccessStream } @@ -1643,42 +1755,45 @@ class ImagePut { extension := "png" pStream := this.put_stream(pBitmap, extension, quality) - DllCall("ole32\GetHGlobalFromStream", "ptr", pStream, "uint*", &hData:=0) - pData := DllCall("GlobalLock", "ptr", hData, "ptr") - nSize := DllCall("GlobalSize", "uint", pData, "uptr") - - ; Using CryptBinaryToStringA saves about 2MB in memory. - DllCall("Crypt32.dll\CryptBinaryToStringA", "ptr", pData, "uint", nSize, "uint", 0x4000000C, "ptr", 0, "uint*", &length:=0) - hex := Buffer(length, 0) - DllCall("Crypt32.dll\CryptBinaryToStringA", "ptr", pData, "uint", nSize, "uint", 0x4000000C, "ptr", hex, "uint*", length) - - DllCall("GlobalUnlock", "ptr", hData) + hex := this.set_hex(pStream) ObjRelease(pStream) + return hex + } - return StrGet(hex, length, "CP0") + static set_hex(pStream) { + return this.set_string(pStream, 0x4000000C) ; CRYPT_STRING_NOCRLF | CRYPT_STRING_HEXRAW } static put_base64(pBitmap, extension := "", quality := "") { - ; Thanks noname - https://www.autohotkey.com/boards/viewtopic.php?style=7&p=144247#p144247 - ; Default extension is PNG for small sizes! if !(extension ~= "^(?i:bmp|dib|rle|jpg|jpeg|jpe|jfif|gif|tif|tiff|png)$") extension := "png" pStream := this.put_stream(pBitmap, extension, quality) - DllCall("ole32\GetHGlobalFromStream", "ptr", pStream, "uint*", &hData:=0) - pData := DllCall("GlobalLock", "ptr", hData, "ptr") - nSize := DllCall("GlobalSize", "uint", pData, "uptr") + base64 := this.set_base64(pStream) + ObjRelease(pStream) + return base64 + } - ; Using CryptBinaryToStringA saves about 2MB in memory. - DllCall("Crypt32.dll\CryptBinaryToStringA", "ptr", pData, "uint", nSize, "uint", 0x40000001, "ptr", 0, "uint*", &length:=0) - base64 := Buffer(length, 0) - DllCall("Crypt32.dll\CryptBinaryToStringA", "ptr", pData, "uint", nSize, "uint", 0x40000001, "ptr", base64, "uint*", length) + static set_base64(pStream) { + return this.set_string(pStream, 0x40000001) ; CRYPT_STRING_NOCRLF | CRYPT_STRING_BASE64 + } - DllCall("GlobalUnlock", "ptr", hData) - ObjRelease(pStream) + static set_string(pStream, flags) { + ; Thanks noname - https://www.autohotkey.com/boards/viewtopic.php?style=7&p=144247#p144247 + + ; For compatibility with SHCreateMemStream do not use GetHGlobalFromStream. + DllCall("shlwapi\IStream_Size", "ptr", pStream, "ptr*", &size:=0, "HRESULT") + bin := Buffer(size) + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") + DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", bin, "uint", size, "HRESULT") - return StrGet(base64, length, "CP0") + ; Using CryptBinaryToStringA saves about 2MB in memory. + DllCall("crypt32\CryptBinaryToStringA", "ptr", bin, "uint", size, "uint", flags, "ptr", 0, "uint*", &length:=0) + str := Buffer(length) + DllCall("crypt32\CryptBinaryToStringA", "ptr", bin, "uint", size, "uint", flags, "ptr", str, "uint*", length) + + return StrGet(str, length, "CP0") } static select_codec(pBitmap, extension, quality, &pCodec, &ep, &ci, &v) { @@ -1687,31 +1802,106 @@ class ImagePut { DllCall("gdiplus\GdipGetImageEncoders", "uint", count, "uint", size, "ptr", ci := Buffer(size)) ; struct ImageCodecInfo - http://www.jose.it-berater.org/gdiplus/reference/structures/imagecodecinfo.htm - loop count + loop { + if (A_Index > count) + throw Error("Could not find a matching encoder for the specified file format.") + idx := (48+7*A_PtrSize)*(A_Index-1) - until InStr(StrGet(NumGet(ci, idx+32+3*A_PtrSize, "ptr"), "UTF-16"), "*." extension) ; FilenameExtension + } until InStr(StrGet(NumGet(ci, idx+32+3*A_PtrSize, "ptr"), "UTF-16"), "*." extension) ; FilenameExtension ; Get the pointer to the clsid of the matching encoder. - if !(pCodec := ci.ptr + idx) ; ClassID - throw Error("Could not find a matching encoder for the specified file format.") + pCodec := ci.ptr + idx ; ClassID ; JPEG default quality is 75. Otherwise set a quality value from [0-100]. - if IsInteger(quality) && ("image/jpeg" = StrGet(NumGet(ci, idx+32+4*A_PtrSize, "ptr"), "UTF-16")) { ; MimeType + if IsInteger(quality) and ("image/jpeg" = StrGet(NumGet(ci, idx+32+4*A_PtrSize, "ptr"), "UTF-16")) { ; MimeType ; Use a separate buffer to store the quality as ValueTypeLong (4). - v := Buffer(4, 0), NumPut("uint", quality, v) + v := Buffer(4), NumPut("uint", quality, v) ; struct EncoderParameter - http://www.jose.it-berater.org/gdiplus/reference/structures/encoderparameter.htm ; enum ValueType - https://docs.microsoft.com/en-us/dotnet/api/system.drawing.imaging.encoderparametervaluetype ; clsid Image Encoder Constants - http://www.jose.it-berater.org/gdiplus/reference/constants/gdipimageencoderconstants.htm ep := Buffer(24+2*A_PtrSize) ; sizeof(EncoderParameter) = ptr + n*(28, 32) NumPut( "uptr", 1, ep, 0) ; Count - DllCall("ole32\CLSIDFromString", "wstr", "{1D5BE4B5-FA4A-452D-9CDD-5DB35105E7EB}", "ptr", ep.ptr+A_PtrSize) + DllCall("ole32\CLSIDFromString", "wstr", "{1D5BE4B5-FA4A-452D-9CDD-5DB35105E7EB}", "ptr", ep.ptr+A_PtrSize, "HRESULT") NumPut( "uint", 1, ep, 16+A_PtrSize) ; Number of Values NumPut( "uint", 4, ep, 20+A_PtrSize) ; Type NumPut( "ptr", v.ptr, ep, 24+A_PtrSize) ; Value } } + static select_extension(pStream, &extension) { + signature := Buffer(12) + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") + DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", signature, "uint", 12, "HRESULT") + + ; This function sniffs the first 12 bytes and matches a known file signature. + ; 256 bytes is recommended, but images only need 12 bytes. + ; See: https://en.wikipedia.org/wiki/List_of_file_signatures + DllCall("urlmon\FindMimeFromData" + , "ptr", 0 ; pBC + , "ptr", 0 ; pwzUrl + , "ptr", signature ; pBuffer + , "uint", 12 ; cbSize + , "ptr", 0 ; pwzMimeProposed + , "uint", 0x20 ; dwMimeFlags + , "ptr*", &MimeType:=0 ; ppwzMimeOut + , "uint", 0 ; dwReserved + ,"HRESULT") + + ; The output is a pointer to a Mime string. It must be dereferenced. + MimeType := StrGet(MimeType, "UTF-16") + + if (MimeType ~= "gif") + extension := "gif" + if (MimeType ~= "jpeg") + extension := "jpg" + if (MimeType ~= "png") + extension := "png" + if (MimeType ~= "tiff") + extension := "tif" + if (MimeType ~= "bmp") + extension := "bmp" + } + + static select_filepath(&filepath, &extension, pStream := "") { + ; Save extension as default. + default := extension + + ; Remove whitespace. Seperate the filepath. Adjust for directories. + filepath := Trim(filepath) + SplitPath filepath,, &directory, &extension, &filename + if DirExist(filepath) + directory .= "\" filename, filename := "" + if (directory != "" && !DirExist(directory)) + DirCreate(directory) + directory := (directory != "") ? directory : "." + + ; Validate filepath. https://stackoverflow.com/a/6804755 + if !(extension ~= "^(?i:bmp|dib|rle|jpg|jpeg|jpe|jfif|gif|tif|tiff|png)$") { + ; If the extension does not match a known file type, append it to the filename. + if (extension != "") + filename .= "." extension + + extension := default + + if (pStream) { + this.select_extension(pStream, &extension) + } + } + filename := RegExReplace(filename, "S)(?i:^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$|[<>:|?*\x00-\x1F\x22\/\\])") + if (filename == "") { + filename := FormatTime(, "yyyy-MM-dd HH?mm?ss") + filepath := directory "\" filename "." extension + if FileExist(filepath) { ; Check for collisions. + loop + filepath := directory "\" filename " (" A_Index ")." extension + until !FileExist(filepath) + } + } + else + filepath := directory "\" filename "." extension + } + ; All references to gdiplus and pToken must be absolute! static gdiplus := 0, pToken := 0 @@ -1775,106 +1965,154 @@ class ImagePut { class ImageEqual extends ImagePut { static call(images*) { + ; Returns false is there are no images to be compared. if (images.length == 0) return false - if (images.length == 1) - return true - this.gdiplusStartup() - ; Convert the images to pBitmaps (byte arrays). + ; Set the first image to its own variable to allow passing by reference. + image := images[1] + + ; Allow the ImageType exception to bubble up. + try type := this.DontVerifyImageType(&image) + catch + type := this.ImageType(image) + + ; Convert only the first image to a bitmap. + if !(pBitmap1 := this.ToBitmap(type, image)) + throw Error("Conversion to bitmap failed. The pointer value is zero.") + + ; If there is only one image, verify that image and return. + if (images.length == 1) { + if DllCall("gdiplus\GdipCloneImage", "ptr", pBitmap1, "ptr*", &pBitmapClone:=0) + throw Error("Validation failed. Unable to access and clone the bitmap.") + + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmapClone) + Goto Good_Ending + } + + ; If there are multiple images, compare each subsequent image to the first. for i, image in images { - try type := this.DontVerifyImageType(image) - catch - try type := this.ImageType(image) - catch { ; Not a valid image. - result := false - break - } - - if (A_Index == 1) { - pBitmap1 := this.toBitmap(type, image) - } else { - pBitmap2 := this.toBitmap(type, image) - result := this.isBitmapEqual(pBitmap1, pBitmap2) + if (A_Index != 1) { + + ; Guess the type of the image. + try type := this.DontVerifyImageType(&image) + catch + type := this.ImageType(image) + + ; Convert the other image to a bitmap. + pBitmap2 := this.ToBitmap(type, image) + + ; Compare the two images. + if !this.BitmapEqual(pBitmap1, pBitmap2) + Goto Bad_Ending ; Exit the loop if the comparison failed. + + ; Cleanup the bitmap. DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap2) - if (result) - continue - else { - result := false - break - } } } + Good_Ending: ; After getting isekai'ed you somehow build a prosperous kingdom and rule the land. DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap1) - this.gdiplusShutdown() + return true - return result + Bad_Ending: ; Turns out your best friend became super jealous of you and killed you in your sleep. + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap2) + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap1) + this.gdiplusShutdown() + return false } - static isBitmapEqual(pBitmap1, pBitmap2, Format := 0x26200A) { - ; Make sure both bitmaps are valid pointers. - if (!pBitmap1 || !pBitmap2) - return false + static BitmapEqual(SourceBitmap1, SourceBitmap2, PixelFormat := 0x26200A) { + ; Make sure both source bitmaps are valid GDI+ pointers. This will throw if not... + DllCall("gdiplus\GdipGetImageType", "ptr", SourceBitmap1, "ptr*", &type1:=0) + DllCall("gdiplus\GdipGetImageType", "ptr", SourceBitmap2, "ptr*", &type2:=0) + + ; ImageTypeUnknown = 0, ImageTypeBitmap = 1, and ImageTypeMetafile = 2. + if (type1 != 1 || type2 != 1) + throw Error("The GDI+ pointer is not a bitmap.") - ; Check if pointers are identical. - if (pBitmap1 == pBitmap2) + ; Check if source bitmap pointers are identical. + if (SourceBitmap1 == SourceBitmap2) return true ; The two bitmaps must be the same size. - DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap1, "uint*", &width1:=0) - DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap2, "uint*", &width2:=0) - DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap1, "uint*", &height1:=0) - DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap2, "uint*", &height2:=0) + DllCall("gdiplus\GdipGetImageWidth", "ptr", SourceBitmap1, "uint*", &width1:=0) + DllCall("gdiplus\GdipGetImageWidth", "ptr", SourceBitmap2, "uint*", &width2:=0) + DllCall("gdiplus\GdipGetImageHeight", "ptr", SourceBitmap1, "uint*", &height1:=0) + DllCall("gdiplus\GdipGetImageHeight", "ptr", SourceBitmap2, "uint*", &height2:=0) + DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", SourceBitmap1, "int*", &format1:=0) + DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", SourceBitmap2, "int*", &format2:=0) + + ; Dimensions must be non-zero. + if !(width1 && width2 && height1 && height2) + throw Error("The bitmap dimensions cannot be zero.") ; Match bitmap dimensions. if (width1 != width2 || height1 != height2) return false + ; Create clones of the supplied source bitmaps in their original PixelFormat. + ; This has the side effect of (1) removing negative stride and solves + ; the problem when (2) both bitmaps reference the same stream and only + ; one of them is able to retrieve the pixel data through LockBits. + ; I assume that instead of locking the stream, the clones lock the originals. + + pBitmap1 := pBitmap2 := 0 + Loop 2 + if DllCall("gdiplus\GdipCloneBitmapAreaI" + , "int", 0 + , "int", 0 + , "int", width%A_Index% + , "int", height%A_Index% + , "int", format%A_Index% + , "ptr", SourceBitmap%A_Index% + , "ptr*", &pBitmap%A_Index%:=0) + throw Error("Cloning Bitmap" A_Index " failed.") + ; struct RECT - https://docs.microsoft.com/en-us/windows/win32/api/windef/ns-windef-rect Rect := Buffer(16, 0) ; sizeof(Rect) = 16 NumPut( "uint", width1, Rect, 8) ; Width NumPut( "uint", height1, Rect, 12) ; Height - ; Do this twice. - while ((i:=IsSet(i)?i:0)++ < 2) { ; for(int i = 1; i <= 2; i++) + ; Create a BitmapData structure. + BitmapData1 := Buffer(16+2*A_PtrSize) ; sizeof(BitmapData) = 24, 32 + BitmapData2 := Buffer(16+2*A_PtrSize) ; sizeof(BitmapData) = 24, 32 - ; Create a BitmapData structure. - BitmapData%i% := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 - - ; Transfer the pixels to a read-only buffer. Avoid using a different PixelFormat. + ; Transfer the pixels to a read-only buffer. The user can declare a PixelFormat. + Loop 2 DllCall("gdiplus\GdipBitmapLockBits" - , "ptr", pBitmap%i% + , "ptr", pBitmap%A_Index% , "ptr", Rect , "uint", 1 ; ImageLockMode.ReadOnly - , "int", Format ; Format32bppArgb is fast. - , "ptr", BitmapData%i%) - - ; Get Stride (number of bytes per horizontal line). - stride%i% := NumGet(BitmapData%i%, 8, "int") - - ; If the Stride is negative, clone the image to make it top-down; redo the loop. - if (stride%i% < 0) { - DllCall("gdiplus\GdipCloneImage", "ptr", pBitmap%i%, "ptr*", &pBitmapClone:=0) - DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap%i%) ; Permanently deletes. - pBitmap%i% := pBitmapClone - i-- ; "Let's go around again! Ha!" https://bit.ly/2AWWcM3 - } + , "int", PixelFormat ; Format32bppArgb is fast. + , "ptr", BitmapData%A_Index%) - ; Get Scan0 (top-left pixel at 0,0). - Scan0%i% := NumGet(BitmapData%i%, 16, "ptr") - } + ; Get Stride (number of bytes per horizontal line). + stride1 := NumGet(BitmapData1, 8, "int") + stride2 := NumGet(BitmapData2, 8, "int") + + ; Well the image has already been cloned, so the stride should never be negative. + if (stride1 < 0 || stride2 < 0) ; See: https://stackoverflow.com/a/10341340 + throw Error("Negative stride. Please report this error to the developer.") + + ; Get Scan0 (top-left pixel at 0,0). + Scan01 := NumGet(BitmapData1, 16, "ptr") + Scan02 := NumGet(BitmapData2, 16, "ptr") ; RtlCompareMemory preforms an unsafe comparison stopping at the first different byte. - size := stride%'1'% * height1 - byte := DllCall("ntdll\RtlCompareMemory", "ptr", Scan0%'1'%, "ptr", Scan0%'2'%, "uptr", size, "uptr") + size := stride1 * height1 + byte := DllCall("ntdll\RtlCompareMemory", "ptr", Scan01, "ptr", Scan02, "uptr", size, "uptr") ; Unlock Bitmaps. Since they were marked as read only there is no copy back. - DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap1, "ptr", BitmapData%'1'%) - DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap2, "ptr", BitmapData%'2'%) + DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap1, "ptr", BitmapData1) + DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap2, "ptr", BitmapData2) + + ; Cleanup bitmap clones. + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap1) + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap2) ; Compare stopped byte. return (byte == size) ? true : false From eee52a4b2fabaa49904ed3efea9e3ad541ca9107 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 7 Oct 2021 19:06:09 -0400 Subject: [PATCH 049/492] v1.2 --- ImagePut (for v1).ahk | 4 ++-- ImagePut.ahk | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 61660546..7af57fde 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1,8 +1,8 @@ ; Script: ImagePut.ahk ; License: MIT License ; Author: Edison Hua (iseahound) -; Date: 2021-09-28 -; Version: v1.1 +; Date: 2021-10-07 +; Version: v1.2 #Requires AutoHotkey v1.1.33+ diff --git a/ImagePut.ahk b/ImagePut.ahk index 98399de4..4d40a17e 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1,8 +1,8 @@ ; Script: ImagePut.ahk ; License: MIT License ; Author: Edison Hua (iseahound) -; Date: 2021-09-28 -; Version: v1.1 +; Date: 2021-10-07 +; Version: v1.2 #Requires AutoHotkey v2.0-beta.1+ From 302e4c9a70ba0835612a99b5640ca443d8945625 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 7 Oct 2021 22:11:12 -0400 Subject: [PATCH 050/492] rename DrawIconEx to user32\DrawIconEx --- ImagePut (for v1).ahk | 4 ++-- ImagePut.ahk | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 7af57fde..692c8859 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -913,7 +913,7 @@ class ImagePut { pBitmap := this.from_hIcon(hCursor) ; Cleanup the handle to the cursor. Same as DestroyIcon. - DllCall("DestroyCursor", "ptr", hCursor) + DllCall("DestroyCursor", "ptr", hCursor) return pBitmap } @@ -1087,7 +1087,7 @@ class ImagePut { , "ptr", &BitmapData) ; Contains the pointer (pBits) to the hbm. ; Don't use DI_DEFAULTSIZE to draw the icon like DrawIcon does as it will resize to 32 x 32. - DllCall("DrawIconEx" + DllCall("user32\DrawIconEx" , "ptr", hdc, "int", 0, "int", 0 , "ptr", image, "int", 0, "int", 0 , "uint", 0, "ptr", 0, "uint", 0x1 | 0x2 | 0x4) ; DI_MASK | DI_IMAGE | DI_COMPAT diff --git a/ImagePut.ahk b/ImagePut.ahk index 4d40a17e..68bb89b3 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -913,7 +913,7 @@ class ImagePut { pBitmap := this.from_hIcon(hCursor) ; Cleanup the handle to the cursor. Same as DestroyIcon. - DllCall("DestroyCursor", "ptr", hCursor) + DllCall("DestroyCursor", "ptr", hCursor) return pBitmap } @@ -1087,7 +1087,7 @@ class ImagePut { , "ptr", BitmapData) ; Contains the pointer (pBits) to the hbm. ; Don't use DI_DEFAULTSIZE to draw the icon like DrawIcon does as it will resize to 32 x 32. - DllCall("DrawIconEx" + DllCall("user32\DrawIconEx" , "ptr", hdc, "int", 0, "int", 0 , "ptr", image, "int", 0, "int", 0 , "uint", 0, "ptr", 0, "uint", 0x1 | 0x2 | 0x4) ; DI_MASK | DI_IMAGE | DI_COMPAT From a67161afb0bd80865c8c887d7589d5d9ec49aef6 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 9 Oct 2021 16:17:57 -0400 Subject: [PATCH 051/492] Add return type for GetObjectType --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 692c8859..29175dff 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -353,7 +353,7 @@ class ImagePut { return "monitor" ; An "hBitmap" is a handle to a GDI Bitmap. - if (DllCall("GetObjectType", "ptr", image) == 7) + if (DllCall("GetObjectType", "ptr", image, "uint") == 7) return "hBitmap" ; An "hIcon" is a handle to a GDI icon. diff --git a/ImagePut.ahk b/ImagePut.ahk index 68bb89b3..6eba1e7e 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -353,7 +353,7 @@ class ImagePut { return "monitor" ; An "hBitmap" is a handle to a GDI Bitmap. - if (DllCall("GetObjectType", "ptr", image) == 7) + if (DllCall("GetObjectType", "ptr", image, "uint") == 7) return "hBitmap" ; An "hIcon" is a handle to a GDI icon. From 0de85d93c23068a3c0a1cd4021d4750694d43deb Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 9 Oct 2021 16:50:15 -0400 Subject: [PATCH 052/492] Release stream in v2 --- ImagePut.ahk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index 6eba1e7e..112674d1 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -921,7 +921,7 @@ class ImagePut { static from_url(image) { pStream := this.get_url(image) DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", &pBitmap:=0) - pStream := "" + ObjRelease(pStream) return pBitmap } From ee6e2bbeaae5057601526ccbc97865dc4d264718 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 9 Oct 2021 17:28:37 -0400 Subject: [PATCH 053/492] Invalid image extensions will throw --- ImagePut (for v1).ahk | 8 ++++---- ImagePut.ahk | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 29175dff..9eb9eebe 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1716,7 +1716,7 @@ class ImagePut { put_stream(pBitmap, extension := "", quality := "") { ; Default extension is TIF for fast speeds! - if !(extension ~= "^(?i:bmp|dib|rle|jpg|jpeg|jpe|jfif|gif|tif|tiff|png)$") + if (extension == "") extension := "tif" ; Select the proper codec based on the extension of the file. @@ -1751,7 +1751,7 @@ class ImagePut { put_hex(pBitmap, extension := "", quality := "") { ; Default extension is PNG for small sizes! - if !(extension ~= "^(?i:bmp|dib|rle|jpg|jpeg|jpe|jfif|gif|tif|tiff|png)$") + if (extension == "") extension := "png" pStream := this.put_stream(pBitmap, extension, quality) @@ -1766,7 +1766,7 @@ class ImagePut { put_base64(pBitmap, extension := "", quality := "") { ; Default extension is PNG for small sizes! - if !(extension ~= "^(?i:bmp|dib|rle|jpg|jpeg|jpe|jfif|gif|tif|tiff|png)$") + if (extension == "") extension := "png" pStream := this.put_stream(pBitmap, extension, quality) @@ -1807,7 +1807,7 @@ class ImagePut { throw Exception("Could not find a matching encoder for the specified file format.") idx := (48+7*A_PtrSize)*(A_Index-1) - } until InStr(StrGet(NumGet(ci, idx+32+3*A_PtrSize, "ptr"), "UTF-16"), "*." extension) ; FilenameExtension + } until InStr(StrGet(NumGet(ci, idx+32+3*A_PtrSize, "ptr"), "UTF-16"), extension) ; FilenameExtension ; Get the pointer to the clsid of the matching encoder. pCodec := &ci + idx ; ClassID diff --git a/ImagePut.ahk b/ImagePut.ahk index 112674d1..375e74bc 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1716,7 +1716,7 @@ class ImagePut { static put_stream(pBitmap, extension := "", quality := "") { ; Default extension is TIF for fast speeds! - if !(extension ~= "^(?i:bmp|dib|rle|jpg|jpeg|jpe|jfif|gif|tif|tiff|png)$") + if (extension == "") extension := "tif" ; Select the proper codec based on the extension of the file. @@ -1751,7 +1751,7 @@ class ImagePut { static put_hex(pBitmap, extension := "", quality := "") { ; Default extension is PNG for small sizes! - if !(extension ~= "^(?i:bmp|dib|rle|jpg|jpeg|jpe|jfif|gif|tif|tiff|png)$") + if (extension == "") extension := "png" pStream := this.put_stream(pBitmap, extension, quality) @@ -1766,7 +1766,7 @@ class ImagePut { static put_base64(pBitmap, extension := "", quality := "") { ; Default extension is PNG for small sizes! - if !(extension ~= "^(?i:bmp|dib|rle|jpg|jpeg|jpe|jfif|gif|tif|tiff|png)$") + if (extension == "") extension := "png" pStream := this.put_stream(pBitmap, extension, quality) @@ -1807,7 +1807,7 @@ class ImagePut { throw Error("Could not find a matching encoder for the specified file format.") idx := (48+7*A_PtrSize)*(A_Index-1) - } until InStr(StrGet(NumGet(ci, idx+32+3*A_PtrSize, "ptr"), "UTF-16"), "*." extension) ; FilenameExtension + } until InStr(StrGet(NumGet(ci, idx+32+3*A_PtrSize, "ptr"), "UTF-16"), extension) ; FilenameExtension ; Get the pointer to the clsid of the matching encoder. pCodec := ci.ptr + idx ; ClassID From 229c80d475f5e96719a9be94e884e4956f102cfe Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 9 Oct 2021 18:00:53 -0400 Subject: [PATCH 054/492] Accept file extensions without the "." --- ImagePut (for v1).ahk | 33 ++++++++++++++++++++++----------- ImagePut.ahk | 33 ++++++++++++++++++++++----------- 2 files changed, 44 insertions(+), 22 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 9eb9eebe..1a672a22 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1864,31 +1864,41 @@ class ImagePut { } select_filepath(ByRef filepath, ByRef extension, pStream := "") { - ; Save extension as default. + ; Save default extension. default := extension - ; Remove whitespace. Seperate the filepath. Adjust for directories. - filepath := Trim(filepath) - SplitPath filepath,, directory, extension, filename + ; Split the filepath. + SplitPath % Trim(filepath),, directory, extension, filename + + ; Check if the entire filepath is a directory. if InStr(FileExist(filepath), "D") directory .= "\" filename, filename := "" + + ; Create a new directory if needed. if (directory != "" && !InStr(FileExist(directory), "D")) FileCreateDir % directory + + ; Default directory is a dot. directory := (directory != "") ? directory : "." - ; Validate filepath. https://stackoverflow.com/a/6804755 + ; Check if the filename is actually the extension. + if (extension == "" && filename ~= "^(?i:bmp|dib|rle|jpg|jpeg|jpe|jfif|gif|tif|tiff|png)$") + extension := filename, filename := "" + + ; Append an invalid extension to the filename. if !(extension ~= "^(?i:bmp|dib|rle|jpg|jpeg|jpe|jfif|gif|tif|tiff|png)$") { - ; If the extension does not match a known file type, append it to the filename. if (extension != "") filename .= "." extension + ; Restore default extension. extension := default - if (pStream) { + ; Try extracting the filetype from the stream. + if (pStream) this.select_extension(pStream, extension) - } } - filename := RegExReplace(filename, "S)(?i:^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$|[<>:|?*\x00-\x1F\x22\/\\])") + + ; Create a filepath based on the timestamp. if (filename == "") { FormatTime, filename,, % "yyyy-MM-dd HH?mm?ss" filepath := directory "\" filename "." extension @@ -1898,8 +1908,9 @@ class ImagePut { until !FileExist(filepath) } } - else - filepath := directory "\" filename "." extension + + ; Filepath is complete! + else filepath := directory "\" filename "." extension } ; All references to gdiplus and pToken must be absolute! diff --git a/ImagePut.ahk b/ImagePut.ahk index 375e74bc..ec872ee2 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1864,31 +1864,41 @@ class ImagePut { } static select_filepath(&filepath, &extension, pStream := "") { - ; Save extension as default. + ; Save default extension. default := extension - ; Remove whitespace. Seperate the filepath. Adjust for directories. - filepath := Trim(filepath) - SplitPath filepath,, &directory, &extension, &filename + ; Split the filepath. + SplitPath Trim(filepath),, &directory, &extension, &filename + + ; Check if the entire filepath is a directory. if DirExist(filepath) directory .= "\" filename, filename := "" + + ; Create a new directory if needed. if (directory != "" && !DirExist(directory)) DirCreate(directory) + + ; Default directory is a dot. directory := (directory != "") ? directory : "." - ; Validate filepath. https://stackoverflow.com/a/6804755 + ; Check if the filename is actually the extension. + if (extension == "" && filename ~= "^(?i:bmp|dib|rle|jpg|jpeg|jpe|jfif|gif|tif|tiff|png)$") + extension := filename, filename := "" + + ; Append an invalid extension to the filename. if !(extension ~= "^(?i:bmp|dib|rle|jpg|jpeg|jpe|jfif|gif|tif|tiff|png)$") { - ; If the extension does not match a known file type, append it to the filename. if (extension != "") filename .= "." extension + ; Restore default extension. extension := default - if (pStream) { + ; Try extracting the filetype from the stream. + if (pStream) this.select_extension(pStream, &extension) - } } - filename := RegExReplace(filename, "S)(?i:^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$|[<>:|?*\x00-\x1F\x22\/\\])") + + ; Create a filepath based on the timestamp. if (filename == "") { filename := FormatTime(, "yyyy-MM-dd HH?mm?ss") filepath := directory "\" filename "." extension @@ -1898,8 +1908,9 @@ class ImagePut { until !FileExist(filepath) } } - else - filepath := directory "\" filename "." extension + + ; Filepath is complete! + else filepath := directory "\" filename "." extension } ; All references to gdiplus and pToken must be absolute! From b5a7c1fcf7301e0e91ceafe3c90b70630510bc3f Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 9 Oct 2021 18:08:12 -0400 Subject: [PATCH 055/492] =?UTF-8?q?rename=20terms*=20=E2=86=92=20p*?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ImagePut (for v1).ahk | 12 ++++++------ ImagePut.ahk | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 1a672a22..948c94e1 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -99,8 +99,8 @@ ImagePutWindow(image, title := "") { return ImagePut("window", image,,, title) } -ImagePut(cotype, image, crop := "", scale := "", terms*) { - return ImagePut.call(cotype, image, crop, scale, terms*) +ImagePut(cotype, image, crop := "", scale := "", p*) { + return ImagePut.call(cotype, image, crop, scale, p*) } @@ -117,8 +117,8 @@ class ImagePut { ; image - Input Image | image -> Anything. Refer to ImageType(). ; crop - Crop Coordinates | array -> [x,y,w,h] could be negative or percent. ; scale - Scale Factor | real -> 2.0 - ; terms* - Additional Parameters | variadic -> Extra parameters found in BitmapToCoimage(). - call(cotype, image, crop := "", scale := "", terms*) { + ; p* - Additional Parameters | variadic -> Extra parameters found in BitmapToCoimage(). + call(cotype, image, crop := "", scale := "", p*) { this.gdiplusStartup() @@ -141,7 +141,7 @@ class ImagePut { ; Convert to a stream intermediate then to the output coimage. pStream := this.ToStream(type, image) - coimage := this.StreamToCoimage(cotype, pStream, terms*) + coimage := this.StreamToCoimage(cotype, pStream, p*) ; Prevents the stream object from being freed. if (cotype = "stream") @@ -181,7 +181,7 @@ class ImagePut { } ; Put the pBitmap to wherever the cotype specifies. - coimage := this.BitmapToCoimage(cotype, pBitmap, terms*) + coimage := this.BitmapToCoimage(cotype, pBitmap, p*) ; Clean up the pBitmap copy. Export raw pointers if requested. if !(cotype = "bitmap" || cotype = "buffer") diff --git a/ImagePut.ahk b/ImagePut.ahk index ec872ee2..7fdb18fd 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -117,8 +117,8 @@ class ImagePut { ; image - Input Image | image -> Anything. Refer to ImageType(). ; crop - Crop Coordinates | array -> [x,y,w,h] could be negative or percent. ; scale - Scale Factor | real -> 2.0 - ; terms* - Additional Parameters | variadic -> Extra parameters found in BitmapToCoimage(). - static call(cotype, image, crop := "", scale := "", terms*) { + ; p* - Additional Parameters | variadic -> Extra parameters found in BitmapToCoimage(). + static call(cotype, image, crop := "", scale := "", p*) { this.gdiplusStartup() @@ -141,7 +141,7 @@ class ImagePut { ; Convert to a stream intermediate then to the output coimage. pStream := this.ToStream(type, image) - coimage := this.StreamToCoimage(cotype, pStream, terms*) + coimage := this.StreamToCoimage(cotype, pStream, p*) ; Prevents the stream object from being freed. if (cotype = "stream") @@ -181,7 +181,7 @@ class ImagePut { } ; Put the pBitmap to wherever the cotype specifies. - coimage := this.BitmapToCoimage(cotype, pBitmap, terms*) + coimage := this.BitmapToCoimage(cotype, pBitmap, p*) ; Clean up the pBitmap copy. Export raw pointers if requested. if !(cotype = "bitmap" || cotype = "buffer") From d3ebe56cdf4be787626590fb5fc112446e5d3cc6 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 9 Oct 2021 18:27:43 -0400 Subject: [PATCH 056/492] File format conversions are reenabled --- ImagePut (for v1).ahk | 3 ++- ImagePut.ahk | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 948c94e1..949148ca 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -137,7 +137,8 @@ class ImagePut { ; Check if a stream can be used as an intermediate. if not this.ForceDecodeImagePixels and not _crop and not _scale and (type ~= "^(?i:url|file|stream|RandomAccessStream|hex|base64)$") - and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64)$") { + and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64)$") + and (p[1] = "") { ; For now, disallow any specification of extensions. ; Convert to a stream intermediate then to the output coimage. pStream := this.ToStream(type, image) diff --git a/ImagePut.ahk b/ImagePut.ahk index 7fdb18fd..0d55848b 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -137,7 +137,8 @@ class ImagePut { ; Check if a stream can be used as an intermediate. if not this.ForceDecodeImagePixels and not _crop and not _scale and (type ~= "^(?i:url|file|stream|RandomAccessStream|hex|base64)$") - and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64)$") { + and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64)$") + and (!p.Has(1) || p[1] == "") { ; For now, disallow any specification of extensions. ; Convert to a stream intermediate then to the output coimage. pStream := this.ToStream(type, image) From fd40810f3c2cd2e02fdae78c2728872d2f919ab6 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 9 Oct 2021 18:51:08 -0400 Subject: [PATCH 057/492] HBitmaps can be negative numbers --- ImagePut (for v1).ahk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 949148ca..8d602769 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -348,7 +348,7 @@ class ImagePut { if FileExist(image) return "file" - if (image ~= "^\d+$") { + if (image ~= "^-?\d+$") { SysGet MonitorGetCount, MonitorCount ; A non-zero "monitor" number identifies each display uniquely; and 0 refers to the entire virtual screen. if (image >= 0 && image <= MonitorGetCount) return "monitor" From e1d8ec8ad14bf7715d5649994d05d2208adb2608 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 9 Oct 2021 19:58:41 -0400 Subject: [PATCH 058/492] Integrate crop and scale parameters into image object --- ImagePut (for v1).ahk | 58 ++++++++++++++++++++++++------------------- ImagePut.ahk | 54 ++++++++++++++++++++++------------------ 2 files changed, 62 insertions(+), 50 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 8d602769..3bdbc70b 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -11,7 +11,7 @@ ; extension - File Encoding | string -> bmp, gif, jpg, png, tiff ; quality - JPEG Quality Level | integer -> 0 - 100 ImagePutBase64(image, extension := "", quality := "") { - return ImagePut("base64", image,,, extension, quality) + return ImagePut("base64", image, extension, quality) } ; Puts the image into a GDI+ Bitmap and returns a pointer. @@ -33,33 +33,32 @@ ImagePutClipboard(image) { ; xHotspot - X Click Point | pixel -> 0 - width ; yHotspot - Y Click Point | pixel -> 0 - height ImagePutCursor(image, xHotspot := "", yHotspot := "") { - return ImagePut("cursor", image,,, xHotspot, yHotspot) + return ImagePut("cursor", image, xHotspot, yHotspot) } ; Puts the image behind the desktop icons and returns the string "desktop". -; scale - Scale Factor | real -> A_ScreenHeight / height. -ImagePutDesktop(image, scale := 1) { - return ImagePut("desktop", image,, scale) +ImagePutDesktop(image) { + return ImagePut("desktop", image) } ; Puts the image into a file and returns a relative filepath. ; filepath - Filepath + Extension | string -> *.bmp, *.gif, *.jpg, *.png, *.tiff ; quality - JPEG Quality Level | integer -> 0 - 100 ImagePutFile(image, filepath := "", quality := "") { - return ImagePut("file", image,,, filepath, quality) + return ImagePut("file", image, filepath, quality) } ; Puts the image into a device independent bitmap and returns the handle. ; alpha - Alpha Replacement Color | RGB -> 0xFFFFFF ImagePutHBitmap(image, alpha := "") { - return ImagePut("hBitmap", image,,, alpha) + return ImagePut("hBitmap", image, alpha) } ; Puts the image into a file format and returns a hexadecimal encoded string. ; extension - File Encoding | string -> bmp, gif, jpg, png, tiff ; quality - JPEG Quality Level | integer -> 0 - 100 ImagePutHex(image, extension := "", quality := "") { - return ImagePut("hex", image,,, extension, quality) + return ImagePut("hex", image, extension, quality) } ; Puts the image into an icon and returns the handle. @@ -71,21 +70,21 @@ ImagePutHIcon(image) { ; extension - File Encoding | string -> bmp, gif, jpg, png, tiff ; quality - JPEG Quality Level | integer -> 0 - 100 ImagePutRandomAccessStream(image, extension := "", quality := "") { - return ImagePut("RandomAccessStream", image,,, extension, quality) + return ImagePut("RandomAccessStream", image, extension, quality) } ; Puts the image on the shared screen device context and returns an array of coordinates. ; screenshot - Screen Coordinates | array -> [x,y,w,h] or [0,0] ; alpha - Alpha Replacement Color | RGB -> 0xFFFFFF ImagePutScreenshot(image, screenshot := "", alpha := "") { - return ImagePut("screenshot", image,,, screenshot, alpha) + return ImagePut("screenshot", image, screenshot, alpha) } ; Puts the image into a file format and returns a pointer to a stream. ; extension - File Encoding | string -> bmp, gif, jpg, png, tiff ; quality - JPEG Quality Level | integer -> 0 - 100 ImagePutStream(image, extension := "", quality := "") { - return ImagePut("stream", image,,, extension, quality) + return ImagePut("stream", image, extension, quality) } ; Puts the image as the desktop wallpaper and returns the string "wallpaper". @@ -96,11 +95,11 @@ ImagePutWallpaper(image) { ; Puts the image in a window and returns a handle to a window. ; title - Window Caption Title | string -> MyTitle ImagePutWindow(image, title := "") { - return ImagePut("window", image,,, title) + return ImagePut("window", image, title) } -ImagePut(cotype, image, crop := "", scale := "", p*) { - return ImagePut.call(cotype, image, crop, scale, p*) +ImagePut(cotype, image, p*) { + return ImagePut.call(cotype, image, p*) } @@ -118,24 +117,31 @@ class ImagePut { ; crop - Crop Coordinates | array -> [x,y,w,h] could be negative or percent. ; scale - Scale Factor | real -> 2.0 ; p* - Additional Parameters | variadic -> Extra parameters found in BitmapToCoimage(). - call(cotype, image, crop := "", scale := "", p*) { + call(cotype, image, p*) { + ; Extract parameters. + crop := IsObject(image.crop) + && image.crop[1] ~= "^-?\d+(\.\d*)?%?$" && image.crop[2] ~= "^-?\d+(\.\d*)?%?$" + && image.crop[3] ~= "^-?\d+(\.\d*)?%?$" && image.crop[4] ~= "^-?\d+(\.\d*)?%?$" + ? image.crop : false + scale := image.scale != 1 && image.scale ~= "^\d+(\.\d+)?$" + ? image.scale : false + + + ; Start! this.gdiplusStartup() - ; Take a guess as to what the image might be. (>90% accuracy!) + ; Dereference the image unknown. + if ObjHasKey(image, "image") + image := image.image + + ; Take a guess as to what the image might be. (>95% accuracy!) try type := this.DontVerifyImageType(image) catch type := this.ImageType(image) - ; Qualify additional parameters for correctness. - _crop := IsObject(crop) - && crop[1] ~= "^-?\d+(\.\d*)?%?$" && crop[2] ~= "^-?\d+(\.\d*)?%?$" - && crop[3] ~= "^-?\d+(\.\d*)?%?$" && crop[4] ~= "^-?\d+(\.\d*)?%?$" - _scale := scale != 1 && scale ~= "^\d+(\.\d+)?$" - - ; Check if a stream can be used as an intermediate. - if not this.ForceDecodeImagePixels and not _crop and not _scale + if not this.ForceDecodeImagePixels and not crop and not scale and (type ~= "^(?i:url|file|stream|RandomAccessStream|hex|base64)$") and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64)$") and (p[1] = "") { ; For now, disallow any specification of extensions. @@ -168,14 +174,14 @@ class ImagePut { DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmap) ; Crop the image. - if (_crop) { + if (crop) { pBitmap2 := this.BitmapCrop(pBitmap, crop) DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) pBitmap := pBitmap2 } ; Scale the image. - if (_scale) { + if (scale) { pBitmap2 := this.BitmapScale(pBitmap, scale) DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) pBitmap := pBitmap2 diff --git a/ImagePut.ahk b/ImagePut.ahk index 0d55848b..a3c47657 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -11,7 +11,7 @@ ; extension - File Encoding | string -> bmp, gif, jpg, png, tiff ; quality - JPEG Quality Level | integer -> 0 - 100 ImagePutBase64(image, extension := "", quality := "") { - return ImagePut("base64", image,,, extension, quality) + return ImagePut("base64", image, extension, quality) } ; Puts the image into a GDI+ Bitmap and returns a pointer. @@ -33,33 +33,32 @@ ImagePutClipboard(image) { ; xHotspot - X Click Point | pixel -> 0 - width ; yHotspot - Y Click Point | pixel -> 0 - height ImagePutCursor(image, xHotspot := "", yHotspot := "") { - return ImagePut("cursor", image,,, xHotspot, yHotspot) + return ImagePut("cursor", image, xHotspot, yHotspot) } ; Puts the image behind the desktop icons and returns the string "desktop". -; scale - Scale Factor | real -> A_ScreenHeight / height. -ImagePutDesktop(image, scale := 1) { - return ImagePut("desktop", image,, scale) +ImagePutDesktop(image) { + return ImagePut("desktop", image) } ; Puts the image into a file and returns a relative filepath. ; filepath - Filepath + Extension | string -> *.bmp, *.gif, *.jpg, *.png, *.tiff ; quality - JPEG Quality Level | integer -> 0 - 100 ImagePutFile(image, filepath := "", quality := "") { - return ImagePut("file", image,,, filepath, quality) + return ImagePut("file", image, filepath, quality) } ; Puts the image into a device independent bitmap and returns the handle. ; alpha - Alpha Replacement Color | RGB -> 0xFFFFFF ImagePutHBitmap(image, alpha := "") { - return ImagePut("hBitmap", image,,, alpha) + return ImagePut("hBitmap", image, alpha) } ; Puts the image into a file format and returns a hexadecimal encoded string. ; extension - File Encoding | string -> bmp, gif, jpg, png, tiff ; quality - JPEG Quality Level | integer -> 0 - 100 ImagePutHex(image, extension := "", quality := "") { - return ImagePut("hex", image,,, extension, quality) + return ImagePut("hex", image, extension, quality) } ; Puts the image into an icon and returns the handle. @@ -71,21 +70,21 @@ ImagePutHIcon(image) { ; extension - File Encoding | string -> bmp, gif, jpg, png, tiff ; quality - JPEG Quality Level | integer -> 0 - 100 ImagePutRandomAccessStream(image, extension := "", quality := "") { - return ImagePut("RandomAccessStream", image,,, extension, quality) + return ImagePut("RandomAccessStream", image, extension, quality) } ; Puts the image on the shared screen device context and returns an array of coordinates. ; screenshot - Screen Coordinates | array -> [x,y,w,h] or [0,0] ; alpha - Alpha Replacement Color | RGB -> 0xFFFFFF ImagePutScreenshot(image, screenshot := "", alpha := "") { - return ImagePut("screenshot", image,,, screenshot, alpha) + return ImagePut("screenshot", image, screenshot, alpha) } ; Puts the image into a file format and returns a pointer to a stream. ; extension - File Encoding | string -> bmp, gif, jpg, png, tiff ; quality - JPEG Quality Level | integer -> 0 - 100 ImagePutStream(image, extension := "", quality := "") { - return ImagePut("stream", image,,, extension, quality) + return ImagePut("stream", image, extension, quality) } ; Puts the image as the desktop wallpaper and returns the string "wallpaper". @@ -96,7 +95,7 @@ ImagePutWallpaper(image) { ; Puts the image in a window and returns a handle to a window. ; title - Window Caption Title | string -> MyTitle ImagePutWindow(image, title := "") { - return ImagePut("window", image,,, title) + return ImagePut("window", image, title) } @@ -118,24 +117,31 @@ class ImagePut { ; crop - Crop Coordinates | array -> [x,y,w,h] could be negative or percent. ; scale - Scale Factor | real -> 2.0 ; p* - Additional Parameters | variadic -> Extra parameters found in BitmapToCoimage(). - static call(cotype, image, crop := "", scale := "", p*) { + static call(cotype, image, p*) { + ; Extract parameters. + crop := image.HasOwnProp("crop") && IsObject(image.crop) + && image.crop[1] ~= "^-?\d+(\.\d*)?%?$" && image.crop[2] ~= "^-?\d+(\.\d*)?%?$" + && image.crop[3] ~= "^-?\d+(\.\d*)?%?$" && image.crop[4] ~= "^-?\d+(\.\d*)?%?$" + ? image.crop : false + scale := image.HasOwnProp("scale") && image.scale != 1 && image.scale ~= "^\d+(\.\d+)?$" + ? image.scale : false + + + ; Start! this.gdiplusStartup() - ; Take a guess as to what the image might be. (>90% accuracy!) + ; Dereference the image unknown. + if ObjHasOwnProp(image, "image") + image := image.image + + ; Take a guess as to what the image might be. (>95% accuracy!) try type := this.DontVerifyImageType(&image) catch type := this.ImageType(image) - ; Qualify additional parameters for correctness. - _crop := IsObject(crop) - && crop[1] ~= "^-?\d+(\.\d*)?%?$" && crop[2] ~= "^-?\d+(\.\d*)?%?$" - && crop[3] ~= "^-?\d+(\.\d*)?%?$" && crop[4] ~= "^-?\d+(\.\d*)?%?$" - _scale := scale != 1 && scale ~= "^\d+(\.\d+)?$" - - ; Check if a stream can be used as an intermediate. - if not this.ForceDecodeImagePixels and not _crop and not _scale + if not this.ForceDecodeImagePixels and not crop and not scale and (type ~= "^(?i:url|file|stream|RandomAccessStream|hex|base64)$") and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64)$") and (!p.Has(1) || p[1] == "") { ; For now, disallow any specification of extensions. @@ -168,14 +174,14 @@ class ImagePut { DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmap) ; Crop the image. - if (_crop) { + if (crop) { pBitmap2 := this.BitmapCrop(pBitmap, crop) DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) pBitmap := pBitmap2 } ; Scale the image. - if (_scale) { + if (scale) { pBitmap2 := this.BitmapScale(pBitmap, scale) DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) pBitmap := pBitmap2 From 2d8a786f35133bc2490d18549a180ed7e102479e Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 9 Oct 2021 20:03:42 -0400 Subject: [PATCH 059/492] replace IsInteger --- ImagePut.ahk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index a3c47657..bf87cee1 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -354,7 +354,7 @@ class ImagePut { if FileExist(image) return "file" - if IsInteger(image) { + if (image ~= "^-?\d+$") { ; A non-zero "monitor" number identifies each display uniquely; and 0 refers to the entire virtual screen. if (image >= 0 && image <= MonitorGetCount()) return "monitor" @@ -1820,7 +1820,7 @@ class ImagePut { pCodec := ci.ptr + idx ; ClassID ; JPEG default quality is 75. Otherwise set a quality value from [0-100]. - if IsInteger(quality) and ("image/jpeg" = StrGet(NumGet(ci, idx+32+4*A_PtrSize, "ptr"), "UTF-16")) { ; MimeType + if (quality ~= "^-?\d+$") and ("image/jpeg" = StrGet(NumGet(ci, idx+32+4*A_PtrSize, "ptr"), "UTF-16")) { ; MimeType ; Use a separate buffer to store the quality as ValueTypeLong (4). v := Buffer(4), NumPut("uint", quality, v) From c8f510cfaf27a3359a8b919b29d22b6da70c1b70 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 9 Oct 2021 20:15:15 -0400 Subject: [PATCH 060/492] Update README.md --- README.md | 166 +++++++++++++----------------------------------------- 1 file changed, 38 insertions(+), 128 deletions(-) diff --git a/README.md b/README.md index a431e720..df25ccdb 100644 --- a/README.md +++ b/README.md @@ -1,146 +1,56 @@ -![transparent hearts](https://i.imgur.com/XSJKgbb.png) # ImagePut -Puts an image from anywhere to anywhere -## Instructions +* Standalone library. +* Easily understandable syntax. +* Fast conversions. +* Highly robust code that has undergone extensive testing. -Download the latest release [here.](https://github.com/iseahound/ImagePut/releases/download/r2021.01.14/ImagePut.v1.zip) -Unzip and run demo.ahk. +## Documentation -Advanced Users: For AutoHotkey v2, please use the [libraries in the v2 folder.](https://github.com/iseahound/ImagePut/blob/master/v2/ImagePut.ahk) +* [Methods and Properties](https://github.com/iseahound/TextRender/wiki/Methods-and-Properties) +* [Background and Text Styles](https://github.com/iseahound/TextRender/wiki/Styles) +* [Tips & Tricks](https://github.com/iseahound/TextRender/wiki/Tips-&-Tricks) -## Windows Image Data Types +#### If you like this and want to see my other AutoHotkey libraries: -Windows stores images in various formats. By formats, I do not mean PNG, JPG, GIF... but rather as a memory bitmap, gdi handle, base 64 data, cursors, image streams, etc. For simplicity those places where images are stored will be referred to as image data types. +* [TextRender & ImageRender](https://github.com/iseahound/TextRender) - Draw text and images to screen. -The purpose of this library is to convert between these data types in a fast and simple manner. For example, if given a pointer to a bitmap, it would be useful to see the image. I can do this by using the function ```ImagePutWindow(pBitmap)``` to quickly display the image. +## So you want to convert an image? -## Features +But you don't how. That's okay because you can just do this: -* Supports reading and writing of multiple data types documented below. -* Fast conversion between all windows image data types. -* Automatic inference of the input data type. - ``` - ; For example the same function can take a file or url as an argument. - ImagePutWindow("https://i.imgur.com/YZk4Rfg.png") - ImagePutWindow("cat.png") - ``` -* Pixel by pixel comparison and verification of image data. -* Independent of Gdip_All. This library utilizes gdiplus.dll directly. -* Simple one line functions that do all the heavy lifting for you. + str := ImagePutBase64("cats.jpg") -## Contributing +or this -Pull requests are welcome! + ImagePutClipboard("https:\\example.com\cats.jpg") + +or something like this: -## Comments, Help, or Feature Requests? Ask questions here. + pStream := ImagePutStream([0, 0, A_ScreenWidth, A_ScreenHeight]) + +Working with images should be this easy. ImagePut has automatic type inference, meaning that it will guess whether the input is (1) a file (2) a website url or (3) a series of coordinates that map to the screen. This functionality enables the user to only memorize a single function for any possible input. For a full list of supported input types, click on the documentation link here. For output types click here. -For the AutoHotkey v1 forum: https://www.autohotkey.com/boards/viewtopic.php?f=6&t=76301 +Converting between file formats is also straightforward. -For the AutoHotkey v2 forum: https://www.autohotkey.com/boards/viewtopic.php?f=83&t=76633 + ; Saves a JPEG as a GIF. + ImagePutFile("cats.jpg", "gif") + +You can also move between different image types and file formats. -# Documentation + ; Returns a base64 encoded GIF. + ImagePutBase64("cats.jpg", "gif") + +There's also some weird functions like ```ImagePutCursor``` which lets you set anything as your cursor. Make sure you don't choose an extremely large image! -### Example Script +Finally, there are several advanced features. The first is the ability to control windows bitmaps directly, through ```ImagePutBitmap``` and ```ImagePutHBitmap```. The second is cropping and scaling functionality. Third is the ability to specify the input type directly. - #include ImageEqual.ahk + ; Declare input type as file. + ImagePutScreenshot({file: "cats.jpg"}) + + ; Scale 2x and crop 10% from each edge. + ImagePutScreenshot({file: "cats.jpg", scale: 2, crop:["-10%", "-10%", "-10%", "-10%"]}) + + ; Unknown image type declared as "image" to be cropped to 200x200 pixels. + ImagePutScreenshot({image: "cats.jpg", crop: [0, 0, 200, 200]}) - ; URL to Base64 (PNG) - str := ImagePutBase64("https://i.imgur.com/YZk4Rfg.png", "png") - - ; Base64 to File (PNG) - ImagePutFile(str, "hearts.png") - - ; Put File on Window - ImagePutWindow("hearts.png", "hearts.png") - - ; Compare images using pixel values. Not file hashes. - ImagePutFile("https://www.autohotkey.com/boards/styles/simplicity/theme/images/logo.png", "ahk.png") - MsgBox % ImageEqual("https://www.autohotkey.com/boards/styles/simplicity/theme/images/logo.png", "ahk.png") ? "Images are equal." : "Images are not equal." - - ; Declaring an input type will skip the detection step, making your code faster and more reliable. - file1 := ImagePutFile({url:"https://www.autohotkey.com/boards/styles/simplicity/theme/images/logo.png"}) - ; Auto Detect Input Type. - file2 := ImagePutFile("https://www.autohotkey.com/boards/styles/simplicity/theme/images/logo.png") - MsgBox % ImageEqual(file1, file2) ? "Images are equal." : "Images are not equal." - -### Output Functions - -**ImagePutBase64** - Returns a base64 string. The image can be encoded using a specifed file format. For JPG images, a quality level can be set as well. Supported file formats: bmp, gif, jpg, png, tiff. Quality: 0 - 100. - -**ImagePutBitmap** - Returns a pointer to a GDI+ bitmap. You are responsible for calling `ImagePut.DisposeImage()` when finished to prevent a GDI+ object leak. Use `ImagePutBuffer` instead. - -**ImagePutBuffer** - Returns a buffer object. This is a smart pointer. It will automatically dispose of the bitmap when the variable is freed, e.g. `buffer := ""`. It also contains its own GDI+ scope, meaning it is not necessary to place `pToken := Gdip_Startup()` at the top of the script. Access the raw pointer via `buffer.pBitmap`. - -**ImagePutClipboard** - Returns an empty string. Puts the image onto the clipboard. - -**ImagePutCursor** - Returns `"A_Cursor"`. Puts the image as the cursor. Specify the cursor hotspot ("click point") using x and y coordinates. - -**ImagePutDesktop** - Returns `"desktop"`. Puts the image on an invisible temporary window behind the desktop icons. This functionality relies on an unsupported and undocumented feature. - -**ImagePutFile** - Returns a filename. Supported file formats: bmp, gif, jpg, png, tiff. Quality: 0 - 100. - -**ImagePutHBitmap** - Returns an hBitmap handle. The pixel format of an hBitmap is in pARGB, so any conversion between pre-multiplied ARGB and ARGB will introduce rounding errors. The result is that any image with transparency will look visually identical to the source, but not be pixel perfect causing `ImageEqual` to fail. RGB images without an alpha channel are unaffected. An alpha color can be specified as the replacement color of transparent pixels. - -**ImagePutHex** - Puts the image into a file format and returns a hexadecimal encoded string. - -**ImagePutHIcon** - Puts the image into an icon and returns the handle. - -**ImagePutRandomAccessStream** - Puts the image into a file format and returns a pointer to a RandomAccessStream. - -**ImagePutScreenshot** - Returns an `[x,y,w,h]` array. Puts the image directly on the screen's device context. Therefore the image will be drawn over by other applications. Takes an `[x,y,w,h]` array. Parameters can be omitted like `[0,0]`. An alpha color can be specified as the replacement color of transparent pixels. - -**ImagePutStream** - Puts the image into a file format and returns a pointer to a stream. - -**ImagePutWallpaper** - Returns `"wallpaper"`. Puts the image as the wallpaper. Whether the image will be streched, filled, tiled, etc. depends on your desktop personalization settings. - -**ImagePutWindow** - Returns a window handle. Displays the image in a window. - -### Cropping and Scaling Images - -**ImagePut(cotype, image, crop := "", scale := "", terms\*)** - -**cotype** - The output type as a string. `"file"` - -**crop** - `[x,y,w,h]` array. Negative values will be subtracted from the edge. Percentages are permitted. `"-20%"` - -**scale** - A real number. Factor to scale by. A scale of `1` does nothing. - -### Input Types - -**base64** - A base64 string, with or without tags i.e. `data:image/png;base64,` - -**bitmap** - A valid pointer to a GDI+ bitmap. - -**buffer** - An object with the `.pBitmap` property. This is a smart pointer to a GDI+ bitmap that is created by `ImagePutBuffer`. - -**clipboard** - The special variable `ClipboardAll` or an empty string `""`. - -**cursor** - The special variable `A_Cursor`. - -**desktop** - The string `"desktop"`. (Case insensitive.) - -**file** - A path to an image file. Supported file formats: bmp, gif, jpg, png, tiff. - -**hBitmap** - A valid handle to a GDI bitmap. If using a transparent hBitmap, know that this format will create visually similar but not pixel identical images due to imprecise division when converting from pARGB to ARGB pixel formats. - -**hIcon** - A valid handle to a GDI icon. - -**object** - A custom object (made by you) that implements a `.Bitmap()` method returning a pointer to a GDI+ bitmap. - -**RandomAccessStream** - A pointer to an IRandomAccessStream interface. - -**screenshot** - `[x,y,w,h]` array. - -**stream** - A pointer to an IStream interface. - -**sprite** - Must be explicitly declared as: `{sprite:"character.bmp"}`. Can be a file or a url. This will sample the top-left pixel and set all pixels of that color as transparent. - -**url** - A url that begins with `https://` or `ftp://`. To override this behavior, declare your url explicitly like `{url:"www.example.com"}`. - -**wallpaper** - The current wallpaper. - -**window** - Any string that matches the window title. Is affected by `SetTitleMatchMode`. Use the special variable `"A"` to match the current active window. Supports `ahk_id`, `ahk_class`, `ahk_pid`, etc. See the AutoHotkey manual for details. - -### Overriding Input Types -Use an object such as `{file:"pic.bmp"}`. This will skip automatic type detection and speed up your script. From 727aa5879e051c336887119e7d00fa97f2cdd84d Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 9 Oct 2021 21:04:07 -0400 Subject: [PATCH 061/492] Update README.md --- README.md | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index df25ccdb..cb91e8e8 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,8 @@ ## Documentation -* [Methods and Properties](https://github.com/iseahound/TextRender/wiki/Methods-and-Properties) -* [Background and Text Styles](https://github.com/iseahound/TextRender/wiki/Styles) -* [Tips & Tricks](https://github.com/iseahound/TextRender/wiki/Tips-&-Tricks) +* [Input Types & Output Functions](https://github.com/iseahound/ImagePut/wiki/Input-Types-&-Output-Functions) +* [Crop, Scale, & Other Flags](https://github.com/iseahound/ImagePut/wiki/Crop,-Scale,-&-Other-Flags) #### If you like this and want to see my other AutoHotkey libraries: @@ -29,7 +28,7 @@ or something like this: pStream := ImagePutStream([0, 0, A_ScreenWidth, A_ScreenHeight]) -Working with images should be this easy. ImagePut has automatic type inference, meaning that it will guess whether the input is (1) a file (2) a website url or (3) a series of coordinates that map to the screen. This functionality enables the user to only memorize a single function for any possible input. For a full list of supported input types, click on the documentation link here. For output types click here. +Working with images should be this easy. ImagePut has automatic type inference, meaning that it will guess whether the input is (1) a file (2) a website url or (3) a series of coordinates that map to the screen. This functionality enables the user to only memorize a single function for any possible input. For a full list of supported input types, click on the documentation link [here](https://github.com/iseahound/ImagePut/wiki/Input-Types-&-Output-Functions#input-types). For output types click [here](https://github.com/iseahound/ImagePut/wiki/Input-Types-&-Output-Functions#output-functions). Converting between file formats is also straightforward. @@ -43,7 +42,7 @@ You can also move between different image types and file formats. There's also some weird functions like ```ImagePutCursor``` which lets you set anything as your cursor. Make sure you don't choose an extremely large image! -Finally, there are several advanced features. The first is the ability to control windows bitmaps directly, through ```ImagePutBitmap``` and ```ImagePutHBitmap```. The second is cropping and scaling functionality. Third is the ability to specify the input type directly. +Finally, there are several advanced features. The first is the ability to ability to specify the [input type](https://github.com/iseahound/ImagePut/wiki/Input-Types-&-Output-Functions#input-types) directly. The second is [cropping](https://github.com/iseahound/ImagePut/wiki/Crop,-Scale,-&-Other-Flags#crop) and [scaling](https://github.com/iseahound/ImagePut/wiki/Crop,-Scale,-&-Other-Flags#scale) functionality. Third is use of ImageEqual() a function that can convert multiple inputs across different windows image data types! ; Declare input type as file. ImagePutScreenshot({file: "cats.jpg"}) @@ -53,4 +52,21 @@ Finally, there are several advanced features. The first is the ability to contro ; Unknown image type declared as "image" to be cropped to 200x200 pixels. ImagePutScreenshot({image: "cats.jpg", crop: [0, 0, 200, 200]}) + + ; Compare a url to a file + MsgBox % ImageEqual("https:\\example.com\cats.jpg", "cats.jpg") + + ; Validate an image as an actual image. + ImageEqual("cats.jpg") + +## Design Philosophy + +ImagePut is designed to be fast. However, because of the nature of ImagePut, it has been deigned to be as fast as possible for many to many, one to many, and many to one operations. If you find that your script relies on a single conversion of one input type to one output type, then you are advised to look at the source code and see what you need. Single conversions can be optimized in ImagePut by declaring an input type as shown above. If you copy and paste my source code, you may get another small gain. For certain operations on Windows that involve specific conversions from one specific file format & input type to another, such as a PNG file in memory to hIcon, there do exist even faster operations that I have not implemented because they are extremely specific and rely on little known behavior. + +## Help and Support + +Come visit the forum for any help, questions, suggestions, etc. + +* v1 forum: https://www.autohotkey.com/boards/viewtopic.php?t=76301 +* v2 forum: https://www.autohotkey.com/boards/viewtopic.php?t=76633 From 9ba5d6b5cc68b83fc80cb10a7bb26499f8e48370 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 9 Oct 2021 21:09:40 -0400 Subject: [PATCH 062/492] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cb91e8e8..f5144256 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ You can also move between different image types and file formats. There's also some weird functions like ```ImagePutCursor``` which lets you set anything as your cursor. Make sure you don't choose an extremely large image! -Finally, there are several advanced features. The first is the ability to ability to specify the [input type](https://github.com/iseahound/ImagePut/wiki/Input-Types-&-Output-Functions#input-types) directly. The second is [cropping](https://github.com/iseahound/ImagePut/wiki/Crop,-Scale,-&-Other-Flags#crop) and [scaling](https://github.com/iseahound/ImagePut/wiki/Crop,-Scale,-&-Other-Flags#scale) functionality. Third is use of ImageEqual() a function that can convert multiple inputs across different windows image data types! +Finally, there are several advanced features. The first is the ability to specify the [input type](https://github.com/iseahound/ImagePut/wiki/Input-Types-&-Output-Functions#input-types) directly. The second is [cropping](https://github.com/iseahound/ImagePut/wiki/Crop,-Scale,-&-Other-Flags#crop) and [scaling](https://github.com/iseahound/ImagePut/wiki/Crop,-Scale,-&-Other-Flags#scale) functionality. Third is use of ImageEqual() a function that can convert multiple inputs across different windows image data types! ; Declare input type as file. ImagePutScreenshot({file: "cats.jpg"}) @@ -61,7 +61,7 @@ Finally, there are several advanced features. The first is the ability to abilit ## Design Philosophy -ImagePut is designed to be fast. However, because of the nature of ImagePut, it has been deigned to be as fast as possible for many to many, one to many, and many to one operations. If you find that your script relies on a single conversion of one input type to one output type, then you are advised to look at the source code and see what you need. Single conversions can be optimized in ImagePut by declaring an input type as shown above. If you copy and paste my source code, you may get another small gain. For certain operations on Windows that involve specific conversions from one specific file format & input type to another, such as a PNG file in memory to hIcon, there do exist even faster operations that I have not implemented because they are extremely specific and rely on little known behavior. +ImagePut is designed to be fast. However, because of the nature of ImagePut, it has been deigned to be as fast as possible for many to many, one to many, and many to one operations. If you find that your script relies on a single conversion of one input type to one output type, then you are advised to look at the source code and see what you need. Single conversions can be optimized in ImagePut by declaring an input type as shown above. If you copy and paste my source code, you may get an additional small gain. For certain operations on Windows that involve specific conversions from one specific file format & input type to another, such as a PNG file in memory to hIcon, there do exist even faster operations that I have not implemented because they are extremely specific and rely on little known behavior. ## Help and Support From 7a453d63369c616da9a698349355209f815db509 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 9 Oct 2021 21:15:04 -0400 Subject: [PATCH 063/492] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f5144256..c8b1a275 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ There's also some weird functions like ```ImagePutCursor``` which lets you set a Finally, there are several advanced features. The first is the ability to specify the [input type](https://github.com/iseahound/ImagePut/wiki/Input-Types-&-Output-Functions#input-types) directly. The second is [cropping](https://github.com/iseahound/ImagePut/wiki/Crop,-Scale,-&-Other-Flags#crop) and [scaling](https://github.com/iseahound/ImagePut/wiki/Crop,-Scale,-&-Other-Flags#scale) functionality. Third is use of ImageEqual() a function that can convert multiple inputs across different windows image data types! ; Declare input type as file. - ImagePutScreenshot({file: "cats.jpg"}) + ImagePutWindow({file: "cats.jpg"}) ; Scale 2x and crop 10% from each edge. ImagePutScreenshot({file: "cats.jpg", scale: 2, crop:["-10%", "-10%", "-10%", "-10%"]}) From 843d885afb4b15412a11cc009db237ddf247367a Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 10 Oct 2021 00:39:36 -0400 Subject: [PATCH 064/492] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c8b1a275..2bdcc342 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ But you don't how. That's okay because you can just do this: or this - ImagePutClipboard("https:\\example.com\cats.jpg") + ImagePutClipboard("https://example.com/cats.jpg") or something like this: @@ -54,7 +54,7 @@ Finally, there are several advanced features. The first is the ability to specif ImagePutScreenshot({image: "cats.jpg", crop: [0, 0, 200, 200]}) ; Compare a url to a file - MsgBox % ImageEqual("https:\\example.com\cats.jpg", "cats.jpg") + MsgBox % ImageEqual("https://example.com/cats.jpg", "cats.jpg") ; Validate an image as an actual image. ImageEqual("cats.jpg") From 87dd2394b8f570f351f6846a40d0ba3b4866db15 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 10 Oct 2021 00:41:47 -0400 Subject: [PATCH 065/492] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2bdcc342..39768509 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ Finally, there are several advanced features. The first is the ability to specif ## Design Philosophy -ImagePut is designed to be fast. However, because of the nature of ImagePut, it has been deigned to be as fast as possible for many to many, one to many, and many to one operations. If you find that your script relies on a single conversion of one input type to one output type, then you are advised to look at the source code and see what you need. Single conversions can be optimized in ImagePut by declaring an input type as shown above. If you copy and paste my source code, you may get an additional small gain. For certain operations on Windows that involve specific conversions from one specific file format & input type to another, such as a PNG file in memory to hIcon, there do exist even faster operations that I have not implemented because they are extremely specific and rely on little known behavior. +ImagePut is designed to be fast. However, because of the nature of ImagePut, it has been designed to be as fast as possible for many to many, one to many, and many to one operations. If you find that your script relies on a single conversion of one input type to one output type, then you are advised to look at the source code and see what you need. Single conversions can be optimized in ImagePut by declaring an input type as shown above. If you copy and paste my source code, you may get an additional small gain. For certain operations on Windows that involve specific conversions from one specific file format & input type to another, such as a PNG file in memory to hIcon, there do exist even faster operations that I have not implemented because they are extremely specific and rely on little known behavior. ## Help and Support From 62ecff25ce7a4ea1ee21f744887fd598350c94f9 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 10 Oct 2021 10:22:55 -0400 Subject: [PATCH 066/492] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 39768509..a82a948e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # ImagePut +* Accepts many [inputs](https://github.com/iseahound/ImagePut/wiki/Input-Types-&-Output-Functions#input-types). * Standalone library. * Easily understandable syntax. * Fast conversions. From fda88d150d3bf1072424520206a1bb297b119916 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 10 Oct 2021 10:25:02 -0400 Subject: [PATCH 067/492] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a82a948e..aac4814a 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ * [Input Types & Output Functions](https://github.com/iseahound/ImagePut/wiki/Input-Types-&-Output-Functions) * [Crop, Scale, & Other Flags](https://github.com/iseahound/ImagePut/wiki/Crop,-Scale,-&-Other-Flags) -#### If you like this and want to see my other AutoHotkey libraries: +If you like this and want to see my other AutoHotkey libraries: * [TextRender & ImageRender](https://github.com/iseahound/TextRender) - Draw text and images to screen. From 6582927278485c52d4c411719c10727899376f03 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 10 Oct 2021 20:00:12 -0400 Subject: [PATCH 068/492] ImagePutWindow scales to user's screen --- ImagePut (for v1).ahk | 11 +++++++++++ ImagePut.ahk | 13 ++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 3bdbc70b..bf588bab 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1383,6 +1383,17 @@ class ImagePut { DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) + balance := width / height > A_ScreenWidth / A_ScreenHeight + if (balance && width > A_ScreenWidth) + scale := (A_ScreenWidth / width), width := A_ScreenWidth, height *= scale + if (!balance && height > A_ScreenHeight) + scale := (A_ScreenHeight / height), height := A_ScreenHeight, width *= scale + if (scale != "") { + pBitmapScale := this.BitmapScale(pBitmap, scale) + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + pBitmap := pBitmapScale + } + cls := this.__class pWndProc := RegisterCallback(this.WindowProc, "Fast",, &this) diff --git a/ImagePut.ahk b/ImagePut.ahk index bf87cee1..6f0efa45 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1383,6 +1383,17 @@ class ImagePut { DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) + balance := width / height > A_ScreenWidth / A_ScreenHeight + if (balance && width > A_ScreenWidth) + scale := (A_ScreenWidth / width), width := A_ScreenWidth, height *= scale + if (!balance && height > A_ScreenHeight) + scale := (A_ScreenHeight / height), height := A_ScreenHeight, width *= scale + if IsSet(scale) { + pBitmapScale := this.BitmapScale(pBitmap, scale) + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + pBitmap := pBitmapScale + } + cls := this.prototype.__class pWndProc := CallbackCreate(WindowProc) @@ -1496,7 +1507,7 @@ class ImagePut { , "ptr", hwnd ; hWnd , "ptr", 0 ; hdcDst ,"uint64*", 0 | 0 << 32 ; *pptDst - ,"uint64*", width | height << 32 ; *psize + ,"uint64*", Integer(width) | Integer(height) << 32 ; *psize , "ptr", hdc ; hdcSrc , "int64*", 0 ; *pptSrc , "uint", 0 ; crKey From 570fec2aedb11b08a589b9c58b1ccc0722cb9702 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 10 Oct 2021 20:09:38 -0400 Subject: [PATCH 069/492] Add IsObject checks --- ImagePut (for v1).ahk | 24 ++++++++++++++---------- ImagePut.ahk | 24 ++++++++++++++---------- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index bf588bab..44dfd5e7 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -119,22 +119,26 @@ class ImagePut { ; p* - Additional Parameters | variadic -> Extra parameters found in BitmapToCoimage(). call(cotype, image, p*) { + crop := scale := false + ; Extract parameters. - crop := IsObject(image.crop) - && image.crop[1] ~= "^-?\d+(\.\d*)?%?$" && image.crop[2] ~= "^-?\d+(\.\d*)?%?$" - && image.crop[3] ~= "^-?\d+(\.\d*)?%?$" && image.crop[4] ~= "^-?\d+(\.\d*)?%?$" - ? image.crop : false - scale := image.scale != 1 && image.scale ~= "^\d+(\.\d+)?$" - ? image.scale : false + if IsObject(image) { + crop := IsObject(image.crop) + && image.crop[1] ~= "^-?\d+(\.\d*)?%?$" && image.crop[2] ~= "^-?\d+(\.\d*)?%?$" + && image.crop[3] ~= "^-?\d+(\.\d*)?%?$" && image.crop[4] ~= "^-?\d+(\.\d*)?%?$" + ? image.crop : false + scale := image.scale != 1 && image.scale ~= "^\d+(\.\d+)?$" + ? image.scale : false + + ; Dereference the image unknown. + if ObjHasKey(image, "image") + image := image.image + } ; Start! this.gdiplusStartup() - ; Dereference the image unknown. - if ObjHasKey(image, "image") - image := image.image - ; Take a guess as to what the image might be. (>95% accuracy!) try type := this.DontVerifyImageType(image) catch diff --git a/ImagePut.ahk b/ImagePut.ahk index 6f0efa45..e683e296 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -119,22 +119,26 @@ class ImagePut { ; p* - Additional Parameters | variadic -> Extra parameters found in BitmapToCoimage(). static call(cotype, image, p*) { + crop := scale := false + ; Extract parameters. - crop := image.HasOwnProp("crop") && IsObject(image.crop) - && image.crop[1] ~= "^-?\d+(\.\d*)?%?$" && image.crop[2] ~= "^-?\d+(\.\d*)?%?$" - && image.crop[3] ~= "^-?\d+(\.\d*)?%?$" && image.crop[4] ~= "^-?\d+(\.\d*)?%?$" - ? image.crop : false - scale := image.HasOwnProp("scale") && image.scale != 1 && image.scale ~= "^\d+(\.\d+)?$" - ? image.scale : false + if IsObject(image) { + crop := image.HasOwnProp("crop") && IsObject(image.crop) + && image.crop[1] ~= "^-?\d+(\.\d*)?%?$" && image.crop[2] ~= "^-?\d+(\.\d*)?%?$" + && image.crop[3] ~= "^-?\d+(\.\d*)?%?$" && image.crop[4] ~= "^-?\d+(\.\d*)?%?$" + ? image.crop : false + scale := image.HasOwnProp("scale") && image.scale != 1 && image.scale ~= "^\d+(\.\d+)?$" + ? image.scale : false + + ; Dereference the image unknown. + if ObjHasOwnProp(image, "image") + image := image.image + } ; Start! this.gdiplusStartup() - ; Dereference the image unknown. - if ObjHasOwnProp(image, "image") - image := image.image - ; Take a guess as to what the image might be. (>95% accuracy!) try type := this.DontVerifyImageType(&image) catch From add5c2de9efe2fb1bf5b4f7e83b572920ba268eb Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 10 Oct 2021 20:22:14 -0400 Subject: [PATCH 070/492] Optional: bitmap operations can be ByRef --- ImagePut (for v1).ahk | 36 +++++++++++++++++++----------------- ImagePut.ahk | 36 +++++++++++++++++++----------------- 2 files changed, 38 insertions(+), 34 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 44dfd5e7..f0278787 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -178,18 +178,12 @@ class ImagePut { DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmap) ; Crop the image. - if (crop) { - pBitmap2 := this.BitmapCrop(pBitmap, crop) - DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) - pBitmap := pBitmap2 - } + if (crop) + this.BitmapCrop(pBitmap, crop) ; Scale the image. - if (scale) { - pBitmap2 := this.BitmapScale(pBitmap, scale) - DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) - pBitmap := pBitmap2 - } + if (scale) + this.BitmapScale(pBitmap, scale) ; Put the pBitmap to wherever the cotype specifies. coimage := this.BitmapToCoimage(cotype, pBitmap, p*) @@ -586,7 +580,7 @@ class ImagePut { return DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) } - BitmapCrop(pBitmap, crop) { + BitmapCrop(ByRef pBitmap, crop, dispose := true) { ; Get Bitmap width, height, and format. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) @@ -629,10 +623,15 @@ class ImagePut { , "ptr", pBitmap , "ptr*", pBitmapCrop:=0) + if (dispose) { + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + pBitmap := pBitmapCrop + } + return pBitmapCrop } - BitmapScale(pBitmap, scale) { + BitmapScale(ByRef pBitmap, scale, dispose := true) { ; Get Bitmap width, height, and format. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) @@ -667,6 +666,12 @@ class ImagePut { ; Clean up the graphics context. DllCall("gdiplus\GdipDeleteGraphics", "ptr", pGraphics) + + if (dispose) { + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + pBitmap := pBitmapScale + } + return pBitmapScale } @@ -1392,11 +1397,8 @@ class ImagePut { scale := (A_ScreenWidth / width), width := A_ScreenWidth, height *= scale if (!balance && height > A_ScreenHeight) scale := (A_ScreenHeight / height), height := A_ScreenHeight, width *= scale - if (scale != "") { - pBitmapScale := this.BitmapScale(pBitmap, scale) - DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) - pBitmap := pBitmapScale - } + if (scale != "") + this.BitmapScale(pBitmap, scale) cls := this.__class pWndProc := RegisterCallback(this.WindowProc, "Fast",, &this) diff --git a/ImagePut.ahk b/ImagePut.ahk index e683e296..45e15457 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -178,18 +178,12 @@ class ImagePut { DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmap) ; Crop the image. - if (crop) { - pBitmap2 := this.BitmapCrop(pBitmap, crop) - DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) - pBitmap := pBitmap2 - } + if (crop) + this.BitmapCrop(&pBitmap, crop) ; Scale the image. - if (scale) { - pBitmap2 := this.BitmapScale(pBitmap, scale) - DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) - pBitmap := pBitmap2 - } + if (scale) + this.BitmapScale(&pBitmap, scale) ; Put the pBitmap to wherever the cotype specifies. coimage := this.BitmapToCoimage(cotype, pBitmap, p*) @@ -586,7 +580,7 @@ class ImagePut { return DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) } - static BitmapCrop(pBitmap, crop) { + static BitmapCrop(&pBitmap, crop, dispose := true) { ; Get Bitmap width, height, and format. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) @@ -629,10 +623,15 @@ class ImagePut { , "ptr", pBitmap , "ptr*", &pBitmapCrop:=0) + if (dispose) { + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + pBitmap := pBitmapCrop + } + return pBitmapCrop } - static BitmapScale(pBitmap, scale) { + static BitmapScale(&pBitmap, scale, dispose := true) { ; Get Bitmap width, height, and format. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) @@ -667,6 +666,12 @@ class ImagePut { ; Clean up the graphics context. DllCall("gdiplus\GdipDeleteGraphics", "ptr", pGraphics) + + if (dispose) { + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + pBitmap := pBitmapScale + } + return pBitmapScale } @@ -1392,11 +1397,8 @@ class ImagePut { scale := (A_ScreenWidth / width), width := A_ScreenWidth, height *= scale if (!balance && height > A_ScreenHeight) scale := (A_ScreenHeight / height), height := A_ScreenHeight, width *= scale - if IsSet(scale) { - pBitmapScale := this.BitmapScale(pBitmap, scale) - DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) - pBitmap := pBitmapScale - } + if IsSet(scale) + this.BitmapScale(&pBitmap, scale) cls := this.prototype.__class pWndProc := CallbackCreate(WindowProc) From 8c7e3474d6cf0913098ba6662eb86a0a75c6b3dd Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 10 Oct 2021 20:27:05 -0400 Subject: [PATCH 071/492] Right click to DestroyWindow --- ImagePut (for v1).ahk | 5 +++++ ImagePut.ahk | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index f0278787..13563bce 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1380,6 +1380,11 @@ class ImagePut { return DllCall("DefWindowProc", "ptr", hwnd, "uint", 0xA1, "uptr", 2, "ptr", 0, "ptr") } + ; WM_RBUTTONDOWN + if (uMsg = 0x204) { + DllCall("DestroyWindow", "ptr", hwnd) + } + return DllCall("DefWindowProc", "ptr", hwnd, "uint", uMsg, "uptr", wParam, "ptr", lParam, "ptr") } diff --git a/ImagePut.ahk b/ImagePut.ahk index 45e15457..6dc6e181 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1381,6 +1381,11 @@ class ImagePut { return DllCall("DefWindowProc", "ptr", hwnd, "uint", 0xA1, "uptr", 2, "ptr", 0, "ptr") } + ; WM_RBUTTONDOWN + if (uMsg = 0x204) { + DllCall("DestroyWindow", "ptr", hwnd) + } + return DllCall("DefWindowProc", "ptr", hwnd, "uint", uMsg, "uptr", wParam, "ptr", lParam, "ptr") } From d4d42cc5374880582716f3cfae43a3f2040696fb Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 10 Oct 2021 20:39:42 -0400 Subject: [PATCH 072/492] Use RButtonUp instead to close window --- ImagePut (for v1).ahk | 4 ++-- ImagePut.ahk | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 13563bce..2e199e05 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1380,8 +1380,8 @@ class ImagePut { return DllCall("DefWindowProc", "ptr", hwnd, "uint", 0xA1, "uptr", 2, "ptr", 0, "ptr") } - ; WM_RBUTTONDOWN - if (uMsg = 0x204) { + ; WM_RBUTTONUP + if (uMsg = 0x205) { DllCall("DestroyWindow", "ptr", hwnd) } diff --git a/ImagePut.ahk b/ImagePut.ahk index 6dc6e181..22fe32ce 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1381,8 +1381,8 @@ class ImagePut { return DllCall("DefWindowProc", "ptr", hwnd, "uint", 0xA1, "uptr", 2, "ptr", 0, "ptr") } - ; WM_RBUTTONDOWN - if (uMsg = 0x204) { + ; WM_RBUTTONUP + if (uMsg = 0x205) { DllCall("DestroyWindow", "ptr", hwnd) } From 1bb41ab9d2fc1cb1faedffc3b0f77221eaf042c2 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 10 Oct 2021 21:29:45 -0400 Subject: [PATCH 073/492] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index aac4814a..7417ed0a 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ You can also move between different image types and file formats. There's also some weird functions like ```ImagePutCursor``` which lets you set anything as your cursor. Make sure you don't choose an extremely large image! -Finally, there are several advanced features. The first is the ability to specify the [input type](https://github.com/iseahound/ImagePut/wiki/Input-Types-&-Output-Functions#input-types) directly. The second is [cropping](https://github.com/iseahound/ImagePut/wiki/Crop,-Scale,-&-Other-Flags#crop) and [scaling](https://github.com/iseahound/ImagePut/wiki/Crop,-Scale,-&-Other-Flags#scale) functionality. Third is use of ImageEqual() a function that can convert multiple inputs across different windows image data types! +Finally, there are several advanced features. The first is the ability to specify the [input type](https://github.com/iseahound/ImagePut/wiki/Input-Types-&-Output-Functions#input-types) directly. The second is [cropping](https://github.com/iseahound/ImagePut/wiki/Crop,-Scale,-&-Other-Flags#crop) and [scaling](https://github.com/iseahound/ImagePut/wiki/Crop,-Scale,-&-Other-Flags#scale) functionality. Third is use of ImageEqual() a function that can compare multiple inputs across different windows image data types! ; Declare input type as file. ImagePutWindow({file: "cats.jpg"}) From ceeb5e7f0bba679f39a4009c6a530c75ca21ddea Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 10 Oct 2021 21:43:28 -0400 Subject: [PATCH 074/492] Destroy parent window --- ImagePut (for v1).ahk | 4 +++- ImagePut.ahk | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 2e199e05..63ce1243 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1382,7 +1382,9 @@ class ImagePut { ; WM_RBUTTONUP if (uMsg = 0x205) { - DllCall("DestroyWindow", "ptr", hwnd) + parent := DllCall("GetParent", "ptr", hwnd, "ptr") + hwnd := (parent != A_ScriptHwnd && parent != 0) ? parent : hwnd + return DllCall("DestroyWindow", "ptr", hwnd) } return DllCall("DefWindowProc", "ptr", hwnd, "uint", uMsg, "uptr", wParam, "ptr", lParam, "ptr") diff --git a/ImagePut.ahk b/ImagePut.ahk index 22fe32ce..3b1a4d22 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1383,7 +1383,9 @@ class ImagePut { ; WM_RBUTTONUP if (uMsg = 0x205) { - DllCall("DestroyWindow", "ptr", hwnd) + parent := DllCall("GetParent", "ptr", hwnd, "ptr") + hwnd := (parent != A_ScriptHwnd && parent != 0) ? parent : hwnd + return DllCall("DestroyWindow", "ptr", hwnd) } return DllCall("DefWindowProc", "ptr", hwnd, "uint", uMsg, "uptr", wParam, "ptr", lParam, "ptr") From 36121ae9307116903a8052340cc4a0c09c12740e Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 11 Oct 2021 23:50:32 -0400 Subject: [PATCH 075/492] condense Buffer into the same line as DllCall --- ImagePut (for v1).ahk | 18 ++++++------------ ImagePut.ahk | 18 ++++++------------ 2 files changed, 12 insertions(+), 24 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 63ce1243..e34ffa00 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -799,8 +799,7 @@ class ImagePut { DllCall("ShowWindow", "ptr", image, "int", 4) ; Get the width and height of the client window. - VarSetCapacity(Rect, 16) ; sizeof(RECT) = 16 - DllCall("GetClientRect", "ptr", image, "ptr", &Rect) + DllCall("GetClientRect", "ptr", image, "ptr", &Rect := VarSetCapacity(Rect, 16)) ; sizeof(RECT) = 16 , width := NumGet(Rect, 8, "int") , height := NumGet(Rect, 12, "int") @@ -845,8 +844,7 @@ class ImagePut { throw Exception("Could not locate hidden window behind desktop.") ; Get the width and height of the client window. - VarSetCapacity(Rect, 16) ; sizeof(RECT) = 16 - DllCall("GetClientRect", "ptr", WorkerW, "ptr", &Rect) + DllCall("GetClientRect", "ptr", WorkerW, "ptr", &Rect := VarSetCapacity(Rect, 16)) ; sizeof(RECT) = 16 , width := NumGet(Rect, 8, "int") , height := NumGet(Rect, 12, "int") @@ -1156,8 +1154,7 @@ class ImagePut { get_RandomAccessStream(image) { ; Note that the returned stream shares a reference count with the original RandomAccessStream. - VarSetCapacity(CLSID, 16) - DllCall("ole32\CLSIDFromString", "wstr", "{0000000C-0000-0000-C000-000000000046}", "ptr", &CLSID, "uint") + DllCall("ole32\CLSIDFromString", "wstr", "{0000000C-0000-0000-C000-000000000046}", "ptr", &CLSID := VarSetCapacity(CLSID, 16), "uint") DllCall("ShCore\CreateStreamOverRandomAccessStream", "ptr", image, "ptr", &CLSID, "ptr*", pStream:=0, "uint") return pStream } @@ -1769,8 +1766,7 @@ class ImagePut { set_RandomAccessStream(pStream) { ; Thanks teadrinker - https://www.autohotkey.com/boards/viewtopic.php?f=6&t=72674 - VarSetCapacity(CLSID, 16) - DllCall("ole32\CLSIDFromString", "wstr", "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}", "ptr", &CLSID, "uint") + DllCall("ole32\CLSIDFromString", "wstr", "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}", "ptr", &CLSID := VarSetCapacity(CLSID, 16), "uint") DllCall("ShCore\CreateRandomAccessStreamOverStream" , "ptr", pStream , "uint", BSOS_PREFERDESTINATIONSTREAM := 1 @@ -1815,9 +1811,8 @@ class ImagePut { ; For compatibility with SHCreateMemStream do not use GetHGlobalFromStream. DllCall("shlwapi\IStream_Size", "ptr", pStream, "ptr*", size:=0, "uint") - VarSetCapacity(bin, size) DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") - DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", &bin, "uint", size, "uint") + DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", &bin := VarSetCapacity(bin, size), "uint", size, "uint") ; Using CryptBinaryToStringA saves about 2MB in memory. DllCall("crypt32\CryptBinaryToStringA", "ptr", &bin, "uint", size, "uint", flags, "ptr", 0, "uint*", length:=0) @@ -1861,9 +1856,8 @@ class ImagePut { } select_extension(pStream, ByRef extension) { - VarSetCapacity(signature, 12) DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") - DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", &signature, "uint", 12, "uint") + DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", &signature := VarSetCapacity(signature, 12), "uint", 12, "uint") ; This function sniffs the first 12 bytes and matches a known file signature. ; 256 bytes is recommended, but images only need 12 bytes. diff --git a/ImagePut.ahk b/ImagePut.ahk index 3b1a4d22..6b0496a0 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -799,8 +799,7 @@ class ImagePut { DllCall("ShowWindow", "ptr", image, "int", 4) ; Get the width and height of the client window. - Rect := Buffer(16) ; sizeof(RECT) = 16 - DllCall("GetClientRect", "ptr", image, "ptr", Rect) + DllCall("GetClientRect", "ptr", image, "ptr", Rect := Buffer(16)) ; sizeof(RECT) = 16 , width := NumGet(Rect, 8, "int") , height := NumGet(Rect, 12, "int") @@ -845,8 +844,7 @@ class ImagePut { throw Error("Could not locate hidden window behind desktop.") ; Get the width and height of the client window. - Rect := Buffer(16) ; sizeof(RECT) = 16 - DllCall("GetClientRect", "ptr", WorkerW, "ptr", Rect) + DllCall("GetClientRect", "ptr", WorkerW, "ptr", Rect := Buffer(16)) ; sizeof(RECT) = 16 , width := NumGet(Rect, 8, "int") , height := NumGet(Rect, 12, "int") @@ -1156,8 +1154,7 @@ class ImagePut { static get_RandomAccessStream(image) { ; Note that the returned stream shares a reference count with the original RandomAccessStream. - CLSID := Buffer(16) - DllCall("ole32\CLSIDFromString", "wstr", "{0000000C-0000-0000-C000-000000000046}", "ptr", CLSID, "HRESULT") + DllCall("ole32\CLSIDFromString", "wstr", "{0000000C-0000-0000-C000-000000000046}", "ptr", CLSID := Buffer(16), "HRESULT") DllCall("ShCore\CreateStreamOverRandomAccessStream", "ptr", image, "ptr", CLSID, "ptr*", &pStream:=0, "HRESULT") return pStream } @@ -1769,8 +1766,7 @@ class ImagePut { static set_RandomAccessStream(pStream) { ; Thanks teadrinker - https://www.autohotkey.com/boards/viewtopic.php?f=6&t=72674 - CLSID := Buffer(16) - DllCall("ole32\CLSIDFromString", "wstr", "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}", "ptr", CLSID, "HRESULT") + DllCall("ole32\CLSIDFromString", "wstr", "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}", "ptr", CLSID := Buffer(16), "HRESULT") DllCall("ShCore\CreateRandomAccessStreamOverStream" , "ptr", pStream , "uint", BSOS_PREFERDESTINATIONSTREAM := 1 @@ -1815,9 +1811,8 @@ class ImagePut { ; For compatibility with SHCreateMemStream do not use GetHGlobalFromStream. DllCall("shlwapi\IStream_Size", "ptr", pStream, "ptr*", &size:=0, "HRESULT") - bin := Buffer(size) DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") - DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", bin, "uint", size, "HRESULT") + DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", bin := Buffer(size), "uint", size, "HRESULT") ; Using CryptBinaryToStringA saves about 2MB in memory. DllCall("crypt32\CryptBinaryToStringA", "ptr", bin, "uint", size, "uint", flags, "ptr", 0, "uint*", &length:=0) @@ -1861,9 +1856,8 @@ class ImagePut { } static select_extension(pStream, &extension) { - signature := Buffer(12) DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") - DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", signature, "uint", 12, "HRESULT") + DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", signature := Buffer(12), "uint", 12, "HRESULT") ; This function sniffs the first 12 bytes and matches a known file signature. ; 256 bytes is recommended, but images only need 12 bytes. From 89224698a0aad9d8f01b42198b139d1548c44d94 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 12 Oct 2021 14:32:51 -0400 Subject: [PATCH 076/492] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 7417ed0a..89fbbee9 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,10 @@ * [Input Types & Output Functions](https://github.com/iseahound/ImagePut/wiki/Input-Types-&-Output-Functions) * [Crop, Scale, & Other Flags](https://github.com/iseahound/ImagePut/wiki/Crop,-Scale,-&-Other-Flags) +Projects using ImagePut: + +* [PaddleOCR-AutoHotkey](https://github.com/telppa/PaddleOCR-AutoHotkey) + If you like this and want to see my other AutoHotkey libraries: * [TextRender & ImageRender](https://github.com/iseahound/TextRender) - Draw text and images to screen. From 8e13beb87d25ed23c7cad83663a99160fbdc2bf8 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 12 Oct 2021 14:33:49 -0400 Subject: [PATCH 077/492] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 89fbbee9..2d3eda42 100644 --- a/README.md +++ b/README.md @@ -13,11 +13,11 @@ Projects using ImagePut: -* [PaddleOCR-AutoHotkey](https://github.com/telppa/PaddleOCR-AutoHotkey) +* [PaddleOCR-AutoHotkey](https://github.com/telppa/PaddleOCR-AutoHotkey) - Best OCR for AutoHotkey If you like this and want to see my other AutoHotkey libraries: -* [TextRender & ImageRender](https://github.com/iseahound/TextRender) - Draw text and images to screen. +* [TextRender & ImageRender](https://github.com/iseahound/TextRender) ## So you want to convert an image? From 30fd5c5027f1cbe292f234c017a097508c5a16ff Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 12 Oct 2021 14:34:03 -0400 Subject: [PATCH 078/492] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2d3eda42..22a80289 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Projects using ImagePut: -* [PaddleOCR-AutoHotkey](https://github.com/telppa/PaddleOCR-AutoHotkey) - Best OCR for AutoHotkey +* [PaddleOCR-AutoHotkey](https://github.com/telppa/PaddleOCR-AutoHotkey) If you like this and want to see my other AutoHotkey libraries: From ab1891dace881bad476643d8f42233b1b4d03b21 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 14 Oct 2021 12:45:52 -0400 Subject: [PATCH 079/492] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 22a80289..9750d034 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ * [Input Types & Output Functions](https://github.com/iseahound/ImagePut/wiki/Input-Types-&-Output-Functions) * [Crop, Scale, & Other Flags](https://github.com/iseahound/ImagePut/wiki/Crop,-Scale,-&-Other-Flags) +* Chinese Documentation (中文) - [这里有一个中文版的使用教程](https://www.autoahk.com/archives/37246) Projects using ImagePut: From c49ae2f53e583fe7a35fc0dadb78511761113c5c Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 14 Oct 2021 13:28:55 -0400 Subject: [PATCH 080/492] organize put_window a bit --- ImagePut (for v1).ahk | 28 ++++++++++++++-------------- ImagePut.ahk | 28 ++++++++++++++-------------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index e34ffa00..90598750 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1392,18 +1392,6 @@ class ImagePut { void := ObjBindMethod({}, {}) Hotkey % "^+F12", % void, On - ; Get Bitmap width and height. - DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) - DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) - - balance := width / height > A_ScreenWidth / A_ScreenHeight - if (balance && width > A_ScreenWidth) - scale := (A_ScreenWidth / width), width := A_ScreenWidth, height *= scale - if (!balance && height > A_ScreenHeight) - scale := (A_ScreenHeight / height), height := A_ScreenHeight, width *= scale - if (scale != "") - this.BitmapScale(pBitmap, scale) - cls := this.__class pWndProc := RegisterCallback(this.WindowProc, "Fast",, &this) @@ -1455,8 +1443,20 @@ class ImagePut { WS_EX_TRANSPARENT := 0x20 WS_EX_DLGMODALFRAME := 0x1 - style := WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_CLIPCHILDREN | WS_POPUP | WS_CLIPSIBLINGS ;| WS_SIZEBOX - styleEx := WS_EX_TOPMOST | WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME ;| WS_EX_LAYERED ;| WS_EX_STATICEDGE + style := WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_CLIPCHILDREN | WS_POPUP | WS_CLIPSIBLINGS ;| WS_SIZEBOX + styleEx := WS_EX_TOPMOST | WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME ;| WS_EX_STATICEDGE + + ; Get Bitmap width and height. + DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) + DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) + + balance := width / height > A_ScreenWidth / A_ScreenHeight + if (balance && width > A_ScreenWidth) + scale := (A_ScreenWidth / width), width := A_ScreenWidth, height *= scale + if (!balance && height > A_ScreenHeight) + scale := (A_ScreenHeight / height), height := A_ScreenHeight, width *= scale + if (scale != "") + this.BitmapScale(pBitmap, scale) VarSetCapacity(rect, 16) NumPut(Floor((A_ScreenWidth - width) / 2), rect, 0, "int") diff --git a/ImagePut.ahk b/ImagePut.ahk index 6b0496a0..921afd5d 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1392,18 +1392,6 @@ class ImagePut { Persistent(true) - ; Get Bitmap width and height. - DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) - DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) - - balance := width / height > A_ScreenWidth / A_ScreenHeight - if (balance && width > A_ScreenWidth) - scale := (A_ScreenWidth / width), width := A_ScreenWidth, height *= scale - if (!balance && height > A_ScreenHeight) - scale := (A_ScreenHeight / height), height := A_ScreenHeight, width *= scale - if IsSet(scale) - this.BitmapScale(&pBitmap, scale) - cls := this.prototype.__class pWndProc := CallbackCreate(WindowProc) @@ -1455,8 +1443,20 @@ class ImagePut { WS_EX_TRANSPARENT := 0x20 WS_EX_DLGMODALFRAME := 0x1 - style := WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_CLIPCHILDREN | WS_POPUP | WS_CLIPSIBLINGS ;| WS_SIZEBOX - styleEx := WS_EX_TOPMOST | WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME ;| WS_EX_LAYERED ;| WS_EX_STATICEDGE + style := WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_CLIPCHILDREN | WS_POPUP | WS_CLIPSIBLINGS ;| WS_SIZEBOX + styleEx := WS_EX_TOPMOST | WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME ;| WS_EX_STATICEDGE + + ; Get Bitmap width and height. + DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) + DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) + + balance := width / height > A_ScreenWidth / A_ScreenHeight + if (balance && width > A_ScreenWidth) + scale := (A_ScreenWidth / width), width := A_ScreenWidth, height *= scale + if (!balance && height > A_ScreenHeight) + scale := (A_ScreenHeight / height), height := A_ScreenHeight, width *= scale + if IsSet(scale) + this.BitmapScale(&pBitmap, scale) rect := Buffer(16) NumPut("int", Floor((A_ScreenWidth - width) / 2), rect, 0) From a8497af38bd0135db91b3558f842d393abe4a884 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 15 Oct 2021 01:29:33 -0400 Subject: [PATCH 081/492] Revamp put_window to include multiple downscaling algoritms * StretchBlt for 24 bpp images * DrawImage for 32 bpp images * LockBits when scaling is not needed. Tentative change, may be reversed or replaced in the future. --- ImagePut.ahk | 263 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 180 insertions(+), 83 deletions(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index 921afd5d..278886c4 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1362,7 +1362,7 @@ class ImagePut { return [x,y,w,h] } - static put_window(pBitmap, title := "") { + static put_window(pBitmap, pos := "", title := "") { WindowProc(hwnd, uMsg, wParam, lParam) { @@ -1443,94 +1443,191 @@ class ImagePut { WS_EX_TRANSPARENT := 0x20 WS_EX_DLGMODALFRAME := 0x1 - style := WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_CLIPCHILDREN | WS_POPUP | WS_CLIPSIBLINGS ;| WS_SIZEBOX + style := WS_CAPTION | WS_SYSMENU | WS_CLIPCHILDREN | WS_POPUP | WS_CLIPSIBLINGS ;| WS_SIZEBOX WS_VISIBLE | styleEx := WS_EX_TOPMOST | WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME ;| WS_EX_STATICEDGE ; Get Bitmap width and height. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) - balance := width / height > A_ScreenWidth / A_ScreenHeight - if (balance && width > A_ScreenWidth) - scale := (A_ScreenWidth / width), width := A_ScreenWidth, height *= scale - if (!balance && height > A_ScreenHeight) - scale := (A_ScreenHeight / height), height := A_ScreenHeight, width *= scale - if IsSet(scale) - this.BitmapScale(&pBitmap, scale) - - rect := Buffer(16) - NumPut("int", Floor((A_ScreenWidth - width) / 2), rect, 0) - NumPut("int", Floor((A_ScreenHeight - height) / 2), rect, 4) - NumPut("int", Floor((A_ScreenWidth + width) / 2), rect, 8) - NumPut("int", Floor((A_ScreenHeight + height) / 2), rect, 12) - - DllCall("AdjustWindowRectEx", "ptr", rect, "uint", style, "uint", 0, "uint", styleEx) - , x := NumGet(rect, 0, "int") - , y := NumGet(rect, 4, "int") - , w := NumGet(rect, 8, "int") - NumGet(rect, 0, "int") - , h := NumGet(rect, 12, "int") - NumGet(rect, 4, "int") - - hwnd0 := DllCall("CreateWindowEx" - , "uint", styleEx - , "str", "ImagePut" ; lpClassName - , "str", title ;"Pichu" ; lpWindowName - , "uint", style - , "int", x ; X - , "int", y ; Y - , "int", w ; nWidth - , "int", h ; nHeight - , "ptr", A_ScriptHwnd ; hWndParent - , "ptr", 0 ; hMenu - , "ptr", 0 ; hInstance - , "ptr", 0 ; lpParam - , "ptr") - - ;if transparent - WinSetTransColor "F0F0F0", hwnd0 - - vWinStyle := WS_VISIBLE | WS_CHILD - vWinExStyle := WS_EX_LAYERED ;| WS_EX_TOPMOST - - hwnd := DllCall("CreateWindowEx" - , "uint", vWinExStyle ; dwExStyle - , "str", "ImagePut" ; lpClassName - , "str", "Pikachu" ; lpWindowName - , "uint", vWinStyle ; dwStyle - , "int", 0 ; X - , "int", 0 ; Y - , "int", width ; nWidth - , "int", height ; nHeight - , "ptr", hwnd0 ; hWndParent - , "ptr", 0 ; hMenu - , "ptr", 0 ; hInstance - , "ptr", 0 ; lpParam - , "ptr") - - ;DllCall("ShowWindow", "ptr", hwnd, "int", 1) - - hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") - hbm := this.put_hBitmap(pBitmap) - obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") - ;DllCall("gdiplus\GdipCreateFromHDC", "ptr", hdc , "ptr*", &gfx:=0) - - DllCall("UpdateLayeredWindow" - , "ptr", hwnd ; hWnd - , "ptr", 0 ; hdcDst - ,"uint64*", 0 | 0 << 32 ; *pptDst - ,"uint64*", Integer(width) | Integer(height) << 32 ; *psize - , "ptr", hdc ; hdcSrc - , "int64*", 0 ; *pptSrc - , "uint", 0 ; crKey - , "uint*", 0xFF << 16 | 0x01 << 24 ; *pblend - , "uint", 2) ; dwFlags - - - - ;MsgBox Format("{:X}", Style) " | " Format("{:X}", WinGetStyle(hwnd0)) - ;MsgBox Format("{:X}", StyleEx) " | " Format("{:X}", WinGetExStyle(hwnd0)) - - ;MsgBox Format("{:X}", vWinStyle) " | " Format("{:X}", WinGetStyle(hwnd)) - ;MsgBox Format("{:X}", vWinExStyle) " | " Format("{:X}", WinGetExStyle(hwnd)) + ; If both dimensions exceed the screen boundaries, compare the aspect ratio of the image + ; to the aspect ratio of the screen to determine the scale factor. Default scale is 1. + s := (width > A_ScreenWidth) && (width / height > A_ScreenWidth / A_ScreenHeight) ? A_ScreenWidth / width + : (height > A_ScreenHeight) && (width / height <= A_ScreenWidth / A_ScreenHeight) ? A_ScreenHeight / height + : 1 + + w := IsObject(pos) && pos.has(3) ? pos[3] : s * width + h := IsObject(pos) && pos.has(4) ? pos[4] : s * height + + x := IsObject(pos) && pos.has(1) ? pos[1] : 0.5*(A_ScreenWidth - w) + y := IsObject(pos) && pos.has(2) ? pos[2] : 0.5*(A_ScreenHeight - h) + + ; Resolve dependent coordinates first, coordinates second, and distances last. + x2 := Round(x + w) + y2 := Round(y + h) + x := Round(x) + y := Round(y) + w := Round(w) + h := Round(h) +/* + if (s != 1) + this.BitmapScale(&pBitmap, s) +*/ + rect := Buffer(16) + NumPut("int", x, rect, 0) + NumPut("int", y, rect, 4) + NumPut("int", x2, rect, 8) + NumPut("int", y2, rect, 12) + + DllCall("AdjustWindowRectEx", "ptr", rect, "uint", style, "uint", 0, "uint", styleEx) + + hwnd0 := DllCall("CreateWindowEx" + , "uint", styleEx + , "str", "ImagePut" ; lpClassName + , "str", title ; lpWindowName + , "uint", style + , "int", NumGet(rect, 0, "int") + , "int", NumGet(rect, 4, "int") + , "int", NumGet(rect, 8, "int") - NumGet(rect, 0, "int") + , "int", NumGet(rect, 12, "int") - NumGet(rect, 4, "int") + , "ptr", A_ScriptHwnd ; hWndParent + , "ptr", 0 ; hMenu + , "ptr", 0 ; hInstance + , "ptr", 0 ; lpParam + , "ptr") + + WinSetTransColor "F0F0F0", hwnd0 + + hwnd := DllCall("CreateWindowEx" + , "uint", WS_EX_LAYERED ; dwExStyle + , "str", cls ; lpClassName + , "str", "Pikachu" ; lpWindowName + , "uint", WS_VISIBLE | WS_CHILD ; dwStyle + , "int", 0 + , "int", 0 + , "int", w + , "int", h + , "ptr", hwnd0 ; hWndParent + , "ptr", 0 ; hMenu + , "ptr", 0 ; hInstance + , "ptr", 0 ; lpParam + , "ptr") + + ; Convert the source pBitmap into a hBitmap manually. + ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader + hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") + bi := Buffer(40, 0) ; sizeof(bi) = 40 + NumPut( "uint", 40, bi, 0) ; Size + NumPut( "int", w, bi, 4) ; Width + NumPut( "int", -h, bi, 8) ; Height - Negative so (0, 0) is top-left. + NumPut("ushort", 1, bi, 12) ; Planes + NumPut("ushort", 32, bi, 14) ; BitCount / BitsPerPixel + hbm := DllCall("CreateDIBSection", "ptr", hdc, "ptr", bi, "uint", 0, "ptr*", &pBits:=0, "ptr", 0, "uint", 0, "ptr") + obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") + + DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", pBitmap, "uint*", &format:=0) + + +if (s = 1) { + ; Transfer data from source pBitmap to an hBitmap manually. + Rect := Buffer(16, 0) ; sizeof(Rect) = 16 + NumPut( "uint", width, Rect, 8) ; Width + NumPut( "uint", height, Rect, 12) ; Height + BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + NumPut( "int", 4 * width, BitmapData, 8) ; Stride + NumPut( "ptr", pBits, BitmapData, 16) ; Scan0 + DllCall("gdiplus\GdipBitmapLockBits" + , "ptr", pBitmap + , "ptr", Rect + , "uint", 5 ; ImageLockMode.UserInputBuffer | ImageLockMode.ReadOnly + , "int", 0xE200B ; Format32bppPArgb + , "ptr", BitmapData) ; Contains the pointer (pBits) to the hbm. + DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", BitmapData) +} +else if ((0xFF00 & format) >> 8 = 24) { + + hdc2 := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") + hbm2 := this.put_hBitmap(pBitmap) + obm2 := DllCall("SelectObject", "ptr", hdc2, "ptr", hbm2, "ptr") + + ; Perform bilinear interpolation. See: https://stackoverflow.com/a/4358798 + DllCall("SetStretchBltMode", "ptr", hdc, "int", 4) ; HALFTONE + + ; Copies a portion of the screen to a new device context. + DllCall("gdi32\StretchBlt" + , "ptr", hdc, "int", 0, "int", 0, "int", w, "int", h + , "ptr", hdc2, "int", 0, "int", 0, "int", width, "int", height + , "uint", 0x00CC0020) ; SRCCOPY + + DllCall("SelectObject", "ptr", hdc2, "ptr", obm2) + DllCall("DeleteObject", "ptr", hbm2) + DllCall("DeleteDC", "ptr", hdc2) + + ; Unfortunately, using HALFTONE destroys the alpha channel. + ; There is no way around it, using SRCPAINT forces COLORONCOLOR (3). + ; See: https://devblogs.microsoft.com/oldnewthing/20210915-00/?p=105687 + + ; Create a single pixel to map onto a device context. + bi := Buffer(40, 0) ; sizeof(bi) = 40 + NumPut( "uint", 40, bi, 0) ; Size + NumPut( "int", 1, bi, 4) ; Width + NumPut( "int", 1, bi, 8) ; Height + NumPut("ushort", 1, bi, 12) ; Planes + NumPut("ushort", 32, bi, 14) ; BitCount / BitsPerPixel + + ; Restore alpha channel to opaque. + DllCall("gdi32\StretchDIBits" + , "ptr", hdc + , "int", 0, "int", 0, "int", w, "int", h + , "int", 0, "int", 0, "int", 1, "int", 1 + , "uint*", 0xFF000000 + , "ptr", bi + , "uint", 0 + , "uint", 0x00EE0086) ; SRCPAINT +} +else { + ; Create a graphics context from the device context. + DllCall("gdiplus\GdipCreateFromHDC", "ptr", hdc , "ptr*", &pGraphics:=0) + + ; Set settings in graphics context. + DllCall("gdiplus\GdipSetPixelOffsetMode", "ptr", pGraphics, "int", 2) ; Half pixel offset. + DllCall("gdiplus\GdipSetCompositingMode", "ptr", pGraphics, "int", 1) ; Overwrite/SourceCopy. + DllCall("gdiplus\GdipSetInterpolationMode", "ptr", pGraphics, "int", 6) ; HighQualityBicubic + + ; Draw Image. + DllCall("gdiplus\GdipCreateImageAttributes", "ptr*", &ImageAttr:=0) + DllCall("gdiplus\GdipSetImageAttributesWrapMode", "ptr", ImageAttr, "int", 3) ; WrapModeTileFlipXY + DllCall("gdiplus\GdipDrawImageRectRectI" + , "ptr", pGraphics + , "ptr", pBitmap + , "int", 0, "int", 0, "int", w, "int", h ; destination rectangle + , "int", 0, "int", 0, "int", width, "int", height ; source rectangle + , "int", 2 + , "ptr", ImageAttr + , "ptr", 0 + , "ptr", 0) + DllCall("gdiplus\GdipDisposeImageAttributes", "ptr", ImageAttr) + + ; Clean up the graphics context. + DllCall("gdiplus\GdipDeleteGraphics", "ptr", pGraphics) +} + + DllCall("UpdateLayeredWindow" + , "ptr", hwnd ; hWnd + , "ptr", 0 ; hdcDst + ,"uint64*", 0 | 0 << 32 ; *pptDst + ,"uint64*", w | h << 32 ; *psize + , "ptr", hdc ; hdcSrc + , "int64*", 0 ; *pptSrc + , "uint", 0 ; crKey + , "uint*", 0xFF << 16 | 0x01 << 24 ; *pblend + , "uint", 2) ; dwFlags + DllCall("ShowWindow", "ptr", hwnd0, "int", 1) + + ; Cleanup the hBitmap and device contexts. + DllCall("SelectObject", "ptr", hdc, "ptr", obm) + DllCall("DeleteObject", "ptr", hbm) + DllCall("DeleteDC", "ptr", hdc) return hwnd0 } From 0d91e4c37836e5b599e2964d1e5e63f2b66d9451 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 16 Oct 2021 22:06:24 -0400 Subject: [PATCH 082/492] Fallback when hBitmap is device dependent --- ImagePut (for v1).ahk | 13 +++++++------ ImagePut.ahk | 5 +++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 90598750..efdf23a9 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -987,9 +987,10 @@ class ImagePut { , width := NumGet(dib, 4, "uint") , height := NumGet(dib, 8, "uint") , bpp := NumGet(dib, 18, "ushort") + , pBits := NumGet(dib, A_PtrSize = 4 ? 20:24, "ptr") - ; Fallback to built-in method if pixels are not 32-bit ARGB. - if (bpp != 32) { ; This built-in version is 120% faster but ignores transparency. + ; Fallback to built-in method if pixels are not 32-bit ARGB or hBitmap is a device dependent bitmap. + if (pBits = 0 || bpp != 32) { ; This built-in version is 120% faster but ignores transparency. DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "ptr", image, "ptr", 0, "ptr*", pBitmap:=0) return pBitmap } @@ -1459,10 +1460,10 @@ class ImagePut { this.BitmapScale(pBitmap, scale) VarSetCapacity(rect, 16) - NumPut(Floor((A_ScreenWidth - width) / 2), rect, 0, "int") - NumPut(Floor((A_ScreenHeight - height) / 2), rect, 4, "int") - NumPut(Floor((A_ScreenWidth + width) / 2), rect, 8, "int") - NumPut(Floor((A_ScreenHeight + height) / 2), rect, 12, "int") + NumPut(Floor((A_ScreenWidth - width) / 2.0), rect, 0, "int") + NumPut(Floor((A_ScreenHeight - height) / 2.0), rect, 4, "int") + NumPut(Floor((A_ScreenWidth + width) / 2.0), rect, 8, "int") + NumPut(Floor((A_ScreenHeight + height) / 2.0), rect, 12, "int") DllCall("AdjustWindowRectEx", "ptr", &rect, "uint", style, "uint", 0, "uint", styleEx) , x := NumGet(rect, 0, "int") diff --git a/ImagePut.ahk b/ImagePut.ahk index 278886c4..a84829a7 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -987,9 +987,10 @@ class ImagePut { , width := NumGet(dib, 4, "uint") , height := NumGet(dib, 8, "uint") , bpp := NumGet(dib, 18, "ushort") + , pBits := NumGet(dib, A_PtrSize = 4 ? 20:24, "ptr") - ; Fallback to built-in method if pixels are not 32-bit ARGB. - if (bpp != 32) { ; This built-in version is 120% faster but ignores transparency. + ; Fallback to built-in method if pixels are not 32-bit ARGB or hBitmap is a device dependent bitmap. + if (pBits = 0 || bpp != 32) { ; This built-in version is 120% faster but ignores transparency. DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "ptr", image, "ptr", 0, "ptr*", &pBitmap:=0) return pBitmap } From 8a840593636a2fae1c3b865757fa78d27d12a779 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 17 Oct 2021 16:27:41 -0400 Subject: [PATCH 083/492] Add from_dc and put_dc --- ImagePut (for v1).ahk | 37 +++++++++++++++++++++++++++++++++++++ ImagePut.ahk | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index efdf23a9..6dc9e716 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -36,6 +36,12 @@ ImagePutCursor(image, xHotspot := "", yHotspot := "") { return ImagePut("cursor", image, xHotspot, yHotspot) } +; Puts the image onto a device context and returns the handle. +; alpha - Alpha Replacement Color | RGB -> 0xFFFFFF +ImagePutDC(image, alpha := "") { + return ImagePut("dc", image, alpha) +} + ; Puts the image behind the desktop icons and returns the string "desktop". ImagePutDesktop(image) { return ImagePut("desktop", image) @@ -262,6 +268,11 @@ class ImagePut { return "monitor" } + if ObjHasKey(image, "dc") { + image := image.dc + return "dc" + } + if ObjHasKey(image, "hBitmap") { image := image.hBitmap return "hBitmap" @@ -357,6 +368,10 @@ class ImagePut { if (image >= 0 && image <= MonitorGetCount) return "monitor" + ; A "dc" is a handle to a GDI device context. + if (DllCall("GetObjectType", "ptr", image, "uint") == 3 || DllCall("GetObjectType", "ptr", image, "uint") == 10) + return "dc" + ; An "hBitmap" is a handle to a GDI Bitmap. if (DllCall("GetObjectType", "ptr", image, "uint") == 7) return "hBitmap" @@ -434,6 +449,9 @@ class ImagePut { if (type = "monitor") return this.from_monitor(image) + if (type = "dc") + return this.from_dc(image) + if (type = "hBitmap") return this.from_hBitmap(image) @@ -498,6 +516,10 @@ class ImagePut { if (cotype = "file") return this.put_file(pBitmap, p1, p2) + ; BitmapToCoimage("dc", pBitmap, alpha) + if (cotype = "dc") + return this.put_dc(pBitmap, p1) + ; BitmapToCoimage("hBitmap", pBitmap, alpha) if (cotype = "hBitmap") return this.put_hBitmap(pBitmap, p1) @@ -979,6 +1001,12 @@ class ImagePut { return this.from_screenshot([x,y,w,h]) } + from_dc(image) { + if !(hbm := DllCall("GetCurrentObject", "ptr", image, "uint", 7)) + throw Exception("The device context has no bitmap selected.") + return this.from_hBitmap(hbm) + } + from_hBitmap(image) { ; struct DIBSECTION - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-dibsection ; struct BITMAP - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmap @@ -1693,6 +1721,15 @@ class ImagePut { return filepath } + put_dc(pBitmap, alpha := "") { + ; This may seem strange, but the hBitmap is selected onto the device context, + ; and therefore cannot be deleted. In addition, the stock bitmap can never be leaked. + hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") + hbm := this.put_hBitmap(pBitmap, alpha) + obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") + return hdc + } + put_hBitmap(pBitmap, alpha := "") { ; Revert to built in functionality if a replacement color is declared. if (alpha != "") { ; This built-in version is about 25% slower. diff --git a/ImagePut.ahk b/ImagePut.ahk index a84829a7..ff74ac3e 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -36,6 +36,12 @@ ImagePutCursor(image, xHotspot := "", yHotspot := "") { return ImagePut("cursor", image, xHotspot, yHotspot) } +; Puts the image onto a device context and returns the handle. +; alpha - Alpha Replacement Color | RGB -> 0xFFFFFF +ImagePutDC(image, alpha := "") { + return ImagePut("dc", image, alpha) +} + ; Puts the image behind the desktop icons and returns the string "desktop". ImagePutDesktop(image) { return ImagePut("desktop", image) @@ -262,6 +268,11 @@ class ImagePut { return "monitor" } + if ObjHasOwnProp(image, "dc") { + image := image.dc + return "dc" + } + if ObjHasOwnProp(image, "hBitmap") { image := image.hBitmap return "hBitmap" @@ -357,6 +368,10 @@ class ImagePut { if (image >= 0 && image <= MonitorGetCount()) return "monitor" + ; A "dc" is a handle to a GDI device context. + if (DllCall("GetObjectType", "ptr", image, "uint") == 3 || DllCall("GetObjectType", "ptr", image, "uint") == 10) + return "dc" + ; An "hBitmap" is a handle to a GDI Bitmap. if (DllCall("GetObjectType", "ptr", image, "uint") == 7) return "hBitmap" @@ -434,6 +449,9 @@ class ImagePut { if (type = "monitor") return this.from_monitor(image) + if (type = "dc") + return this.from_dc(image) + if (type = "hBitmap") return this.from_hBitmap(image) @@ -498,6 +516,10 @@ class ImagePut { if (cotype = "file") return this.put_file(pBitmap, p1, p2) + ; BitmapToCoimage("dc", pBitmap, alpha) + if (cotype = "dc") + return this.put_dc(pBitmap, p1) + ; BitmapToCoimage("hBitmap", pBitmap, alpha) if (cotype = "hBitmap") return this.put_hBitmap(pBitmap, p1) @@ -979,6 +1001,12 @@ class ImagePut { return this.from_screenshot([x,y,w,h]) } + static from_dc(image) { + if !(hbm := DllCall("GetCurrentObject", "ptr", image, "uint", 7)) + throw Error("The device context has no bitmap selected.") + return this.from_hBitmap(hbm) + } + static from_hBitmap(image) { ; struct DIBSECTION - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-dibsection ; struct BITMAP - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmap @@ -1790,6 +1818,15 @@ else { return filepath } + static put_dc(pBitmap, alpha := "") { + ; This may seem strange, but the hBitmap is selected onto the device context, + ; and therefore cannot be deleted. In addition, the stock bitmap can never be leaked. + hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") + hbm := this.put_hBitmap(pBitmap, alpha) + obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") + return hdc + } + static put_hBitmap(pBitmap, alpha := "") { ; Revert to built in functionality if a replacement color is declared. if (alpha != "") { ; This built-in version is about 25% slower. From 56d3d551cca94b8703d334a9211cb132690d0b12 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 17 Oct 2021 18:51:40 -0400 Subject: [PATCH 084/492] Standardize hBitmap to hbm --- ImagePut (for v1).ahk | 16 ++++++++-------- ImagePut.ahk | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 6dc9e716..7bc4eb5e 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -756,10 +756,10 @@ class ImagePut { ; Fallback to CF_BITMAP. This format does not support transparency even with put_hBitmap(). else if DllCall("IsClipboardFormatAvailable", "uint", 2) { - if !(hBitmap := DllCall("GetClipboardData", "uint", 2, "ptr")) + if !(hbm := DllCall("GetClipboardData", "uint", 2, "ptr")) throw Exception("Shared clipboard data has been deleted.") - DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "ptr", hBitmap, "ptr", 0, "ptr*", pBitmap:=0) - DllCall("DeleteObject", "ptr", hBitmap) + DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "ptr", hbm, "ptr", 0, "ptr*", pBitmap:=0) + DllCall("DeleteObject", "ptr", hbm) } DllCall("CloseClipboard") @@ -1311,12 +1311,12 @@ class ImagePut { ; #2 - Place the image onto the clipboard in the CF_DIB format using a bottom-up bitmap. ; Thanks tic - https://www.autohotkey.com/boards/viewtopic.php?t=6517 - DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", "ptr", pBitmap, "ptr*", hBitmap:=0, "uint", 0) + DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", "ptr", pBitmap, "ptr*", hbm:=0, "uint", 0) ; struct DIBSECTION - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-dibsection ; struct BITMAP - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmap VarSetCapacity(dib, size := 64+5*A_PtrSize) ; sizeof(DIBSECTION) = 84, 104 - DllCall("GetObject", "ptr", hBitmap, "int", size, "ptr", &dib) + DllCall("GetObject", "ptr", hbm, "int", size, "ptr", &dib) , pBits := NumGet(dib, A_PtrSize = 4 ? 20:24, "ptr") ; bmBits , size := NumGet(dib, A_PtrSize = 4 ? 44:52, "uint") ; biSizeImage @@ -1334,7 +1334,7 @@ class ImagePut { DllCall("GlobalUnlock", "ptr", hdib) ; Delete the temporary hBitmap. - DllCall("DeleteObject", "ptr", hBitmap) + DllCall("DeleteObject", "ptr", hbm) ; CF_DIB (8) can be synthesized into CF_BITMAP (2), CF_PALETTE (9), and CF_DIBV5 (17). DllCall("SetClipboardData", "uint", 8, "ptr", hdib) @@ -1733,8 +1733,8 @@ class ImagePut { put_hBitmap(pBitmap, alpha := "") { ; Revert to built in functionality if a replacement color is declared. if (alpha != "") { ; This built-in version is about 25% slower. - DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", "ptr", pBitmap, "ptr*", hBitmap:=0, "uint", alpha) - return hBitmap + DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", "ptr", pBitmap, "ptr*", hbm:=0, "uint", alpha) + return hbm } ; Get Bitmap width and height. diff --git a/ImagePut.ahk b/ImagePut.ahk index ff74ac3e..e2fb0d4a 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -756,10 +756,10 @@ class ImagePut { ; Fallback to CF_BITMAP. This format does not support transparency even with put_hBitmap(). else if DllCall("IsClipboardFormatAvailable", "uint", 2) { - if !(hBitmap := DllCall("GetClipboardData", "uint", 2, "ptr")) + if !(hbm := DllCall("GetClipboardData", "uint", 2, "ptr")) throw Error("Shared clipboard data has been deleted.") - DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "ptr", hBitmap, "ptr", 0, "ptr*", &pBitmap:=0) - DllCall("DeleteObject", "ptr", hBitmap) + DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "ptr", hbm, "ptr", 0, "ptr*", &pBitmap:=0) + DllCall("DeleteObject", "ptr", hbm) } DllCall("CloseClipboard") @@ -1311,12 +1311,12 @@ class ImagePut { ; #2 - Place the image onto the clipboard in the CF_DIB format using a bottom-up bitmap. ; Thanks tic - https://www.autohotkey.com/boards/viewtopic.php?t=6517 - DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", "ptr", pBitmap, "ptr*", &hBitmap:=0, "uint", 0) + DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", "ptr", pBitmap, "ptr*", &hbm:=0, "uint", 0) ; struct DIBSECTION - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-dibsection ; struct BITMAP - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmap dib := Buffer(64+5*A_PtrSize) ; sizeof(DIBSECTION) = 84, 104 - DllCall("GetObject", "ptr", hBitmap, "int", dib.size, "ptr", dib) + DllCall("GetObject", "ptr", hbm, "int", dib.size, "ptr", dib) , pBits := NumGet(dib, A_PtrSize = 4 ? 20:24, "ptr") ; bmBits , size := NumGet(dib, A_PtrSize = 4 ? 44:52, "uint") ; biSizeImage @@ -1334,7 +1334,7 @@ class ImagePut { DllCall("GlobalUnlock", "ptr", hdib) ; Delete the temporary hBitmap. - DllCall("DeleteObject", "ptr", hBitmap) + DllCall("DeleteObject", "ptr", hbm) ; CF_DIB (8) can be synthesized into CF_BITMAP (2), CF_PALETTE (9), and CF_DIBV5 (17). DllCall("SetClipboardData", "uint", 8, "ptr", hdib) @@ -1830,8 +1830,8 @@ else { static put_hBitmap(pBitmap, alpha := "") { ; Revert to built in functionality if a replacement color is declared. if (alpha != "") { ; This built-in version is about 25% slower. - DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", "ptr", pBitmap, "ptr*", &hBitmap:=0, "uint", alpha) - return hBitmap + DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", "ptr", pBitmap, "ptr*", &hbm:=0, "uint", alpha) + return hbm } ; Get Bitmap width and height. From eba2cc4d2adb1ff25e8757cc4c2774fcb0497faf Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 18 Oct 2021 11:52:17 -0400 Subject: [PATCH 085/492] typo --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 7bc4eb5e..34a54d06 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -69,7 +69,7 @@ ImagePutHex(image, extension := "", quality := "") { ; Puts the image into an icon and returns the handle. ImagePutHIcon(image) { - return ImagePut("hBitmap", image) + return ImagePut("hIcon", image) } ; Puts the image into a file format and returns a pointer to a RandomAccessStream. diff --git a/ImagePut.ahk b/ImagePut.ahk index e2fb0d4a..a26486dd 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -69,7 +69,7 @@ ImagePutHex(image, extension := "", quality := "") { ; Puts the image into an icon and returns the handle. ImagePutHIcon(image) { - return ImagePut("hBitmap", image) + return ImagePut("hIcon", image) } ; Puts the image into a file format and returns a pointer to a RandomAccessStream. From 9a9cc1b473e3bc37349f113e41ddc5065f776052 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 18 Oct 2021 22:58:30 -0400 Subject: [PATCH 086/492] Static flags can now be local --- ImagePut (for v1).ahk | 9 +++++++-- ImagePut.ahk | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 34a54d06..7a763e77 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -135,12 +135,17 @@ class ImagePut { ? image.crop : false scale := image.scale != 1 && image.scale ~= "^\d+(\.\d+)?$" ? image.scale : false + ForceDecodeImagePixels := image.ForceDecodeImagePixels + ForcePushImageToMemory := image.ForcePushImageToMemory ; Dereference the image unknown. if ObjHasKey(image, "image") image := image.image } + ForceDecodeImagePixels := this.ForceDecodeImagePixels ? true : ForceDecodeImagePixels ? true : false + ForcePushImageToMemory := this.ForcePushImageToMemory ? true : ForcePushImageToMemory ? true : false + ; Start! this.gdiplusStartup() @@ -151,7 +156,7 @@ class ImagePut { type := this.ImageType(image) ; Check if a stream can be used as an intermediate. - if not this.ForceDecodeImagePixels and not crop and not scale + if not ForceDecodeImagePixels and not crop and not scale and (type ~= "^(?i:url|file|stream|RandomAccessStream|hex|base64)$") and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64)$") and (p[1] = "") { ; For now, disallow any specification of extensions. @@ -180,7 +185,7 @@ class ImagePut { ; and bypasses any copy-on-write and copy on LockBits read behavior. ; This must be called immediately after the pBitmap is created ; or it will fail without throwing any errors. - if (this.ForcePushImageToMemory) + if (ForcePushImageToMemory) DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmap) ; Crop the image. diff --git a/ImagePut.ahk b/ImagePut.ahk index a26486dd..b152bbf2 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -135,12 +135,17 @@ class ImagePut { ? image.crop : false scale := image.HasOwnProp("scale") && image.scale != 1 && image.scale ~= "^\d+(\.\d+)?$" ? image.scale : false + ForceDecodeImagePixels := image.HasOwnProp("ForceDecodeImagePixels") ? image.ForceDecodeImagePixels : false + ForcePushImageToMemory := image.HasOwnProp("ForcePushImageToMemory") ? image.ForcePushImageToMemory : false ; Dereference the image unknown. if ObjHasOwnProp(image, "image") image := image.image } + ForceDecodeImagePixels := this.ForceDecodeImagePixels ? true : IsSet(ForceDecodeImagePixels) ? true : false + ForcePushImageToMemory := this.ForcePushImageToMemory ? true : IsSet(ForcePushImageToMemory) ? true : false + ; Start! this.gdiplusStartup() @@ -151,7 +156,7 @@ class ImagePut { type := this.ImageType(image) ; Check if a stream can be used as an intermediate. - if not this.ForceDecodeImagePixels and not crop and not scale + if not ForceDecodeImagePixels and not crop and not scale and (type ~= "^(?i:url|file|stream|RandomAccessStream|hex|base64)$") and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64)$") and (!p.Has(1) || p[1] == "") { ; For now, disallow any specification of extensions. @@ -180,7 +185,7 @@ class ImagePut { ; and bypasses any copy-on-write and copy on LockBits read behavior. ; This must be called immediately after the pBitmap is created ; or it will fail without throwing any errors. - if (this.ForcePushImageToMemory) + if (ForcePushImageToMemory) DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmap) ; Crop the image. From 3552570b5fab45457d62820efe672bd58b77ec3c Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 18 Oct 2021 23:04:06 -0400 Subject: [PATCH 087/492] sources for dll functions --- ImagePut (for v1).ahk | 6 +++--- ImagePut.ahk | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 7a763e77..086f274b 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -842,7 +842,7 @@ class ImagePut { obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") ; Print the window onto the hBitmap using an undocumented flag. https://stackoverflow.com/a/40042587 - DllCall("PrintWindow", "ptr", image, "ptr", hdc, "uint", 0x3) ; PW_RENDERFULLCONTENT | PW_CLIENTONLY + DllCall("user32\PrintWindow", "ptr", image, "ptr", hdc, "uint", 0x3) ; PW_RENDERFULLCONTENT | PW_CLIENTONLY ; Additional info on how this is implemented: https://www.reddit.com/r/windows/comments/8ffr56/altprintscreen/ ; Convert the hBitmap to a Bitmap using a built in function as there is no transparency. @@ -924,8 +924,8 @@ class ImagePut { hbm := DllCall("CreateDIBSection", "ptr", hdc, "ptr", &bi, "uint", 0, "ptr*", pBits:=0, "ptr", 0, "uint", 0, "ptr") obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") - ; Paints the desktop. - DllCall("PaintDesktop", "ptr", hdc) + ; Paints the wallpaper. + DllCall("user32\PaintDesktop", "ptr", hdc) ; Convert the hBitmap to a Bitmap using a built in function as there is no transparency. DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "ptr", hbm, "ptr", 0, "ptr*", pBitmap:=0) diff --git a/ImagePut.ahk b/ImagePut.ahk index b152bbf2..100d87c1 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -842,7 +842,7 @@ class ImagePut { obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") ; Print the window onto the hBitmap using an undocumented flag. https://stackoverflow.com/a/40042587 - DllCall("PrintWindow", "ptr", image, "ptr", hdc, "uint", 0x3) ; PW_RENDERFULLCONTENT | PW_CLIENTONLY + DllCall("user32\PrintWindow", "ptr", image, "ptr", hdc, "uint", 0x3) ; PW_RENDERFULLCONTENT | PW_CLIENTONLY ; Additional info on how this is implemented: https://www.reddit.com/r/windows/comments/8ffr56/altprintscreen/ ; Convert the hBitmap to a Bitmap using a built in function as there is no transparency. @@ -924,8 +924,8 @@ class ImagePut { hbm := DllCall("CreateDIBSection", "ptr", hdc, "ptr", bi, "uint", 0, "ptr*", &pBits:=0, "ptr", 0, "uint", 0, "ptr") obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") - ; Paints the desktop. - DllCall("PaintDesktop", "ptr", hdc) + ; Paints the wallpaper. + DllCall("user32\PaintDesktop", "ptr", hdc) ; Convert the hBitmap to a Bitmap using a built in function as there is no transparency. DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "ptr", hbm, "ptr", 0, "ptr*", &pBitmap:=0) From 33d139f49fb454dec054b2d52b045c7c4ed0a0d3 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 18 Oct 2021 23:08:47 -0400 Subject: [PATCH 088/492] Stock Bitmap always referred to as obm --- ImagePut (for v1).ahk | 4 ++-- ImagePut.ahk | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 086f274b..5c85c798 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1030,7 +1030,7 @@ class ImagePut { ; Create a handle to a device context and associate the image. sdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") ; Creates a memory DC compatible with the current screen. - sbm := DllCall("SelectObject", "ptr", sdc, "ptr", image, "ptr") ; Put the (hBitmap) image onto the device context. + obm := DllCall("SelectObject", "ptr", sdc, "ptr", image, "ptr") ; Put the (hBitmap) image onto the device context. ; Create a device independent bitmap with negative height. All DIBs use the screen pixel format (pARGB). ; Use hbm to buffer the image such that top-down and bottom-up images are mapped to this top-down buffer. @@ -1078,7 +1078,7 @@ class ImagePut { DllCall("SelectObject", "ptr", hdc, "ptr", obm) DllCall("DeleteObject", "ptr", hbm) DllCall("DeleteDC", "ptr", hdc) - DllCall("SelectObject", "ptr", sdc, "ptr", sbm) + DllCall("SelectObject", "ptr", sdc, "ptr", obm) DllCall("DeleteDC", "ptr", sdc) return pBitmap diff --git a/ImagePut.ahk b/ImagePut.ahk index 100d87c1..80633fb5 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1030,7 +1030,7 @@ class ImagePut { ; Create a handle to a device context and associate the image. sdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") ; Creates a memory DC compatible with the current screen. - sbm := DllCall("SelectObject", "ptr", sdc, "ptr", image, "ptr") ; Put the (hBitmap) image onto the device context. + obm := DllCall("SelectObject", "ptr", sdc, "ptr", image, "ptr") ; Put the (hBitmap) image onto the device context. ; Create a device independent bitmap with negative height. All DIBs use the screen pixel format (pARGB). ; Use hbm to buffer the image such that top-down and bottom-up images are mapped to this top-down buffer. @@ -1078,7 +1078,7 @@ class ImagePut { DllCall("SelectObject", "ptr", hdc, "ptr", obm) DllCall("DeleteObject", "ptr", hbm) DllCall("DeleteDC", "ptr", hdc) - DllCall("SelectObject", "ptr", sdc, "ptr", sbm) + DllCall("SelectObject", "ptr", sdc, "ptr", obm) DllCall("DeleteDC", "ptr", sdc) return pBitmap From 347642dd2c80b0980c81c8c639494bd20249b7ed Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 18 Oct 2021 23:12:04 -0400 Subject: [PATCH 089/492] v1.3 --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 5c85c798..e3cb818a 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2,7 +2,7 @@ ; License: MIT License ; Author: Edison Hua (iseahound) ; Date: 2021-10-07 -; Version: v1.2 +; Version: v1.3 #Requires AutoHotkey v1.1.33+ diff --git a/ImagePut.ahk b/ImagePut.ahk index 80633fb5..86bfb7bb 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2,7 +2,7 @@ ; License: MIT License ; Author: Edison Hua (iseahound) ; Date: 2021-10-07 -; Version: v1.2 +; Version: v1.3 #Requires AutoHotkey v2.0-beta.1+ From 5140ff00ed84f537de157f12f96e9e3a326c5592 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 19 Oct 2021 22:09:13 -0400 Subject: [PATCH 090/492] Fix memory leak in put_window --- ImagePut (for v1).ahk | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index e3cb818a..5c42f034 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1566,6 +1566,11 @@ class ImagePut { ;MsgBox Format("{:X}", vWinStyle) " | " Format("{:X}", WinGetStyle(hwnd)) ;MsgBox Format("{:X}", vWinExStyle) " | " Format("{:X}", WinGetExStyle(hwnd)) + ; Cleanup the hBitmap and device contexts. + DllCall("SelectObject", "ptr", hdc, "ptr", obm) + DllCall("DeleteObject", "ptr", hbm) + DllCall("DeleteDC", "ptr", hdc) + return hwnd0 } From 19a075b9cf14981d2ec7f9aa5a74ab02f936a39c Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 19 Oct 2021 22:20:28 -0400 Subject: [PATCH 091/492] Obsolete cursors removed due to memory leak --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 5c42f034..f099f85a 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1676,7 +1676,7 @@ class ImagePut { } ; Loop over all 16 system cursors and change them all to the new cursor. - SystemCursors := "32512,32513,32514,32515,32516,32640,32641,32642,32643,32644,32645,32646,32648,32649,32650,32651" + SystemCursors := "32512,32513,32514,32515,32516,32642,32643,32644,32645,32646,32648,32649,32650,32651" Loop Parse, SystemCursors, % "," { ; Must copy the handle 16 times as SetSystemCursor deletes the handle 16 times. hCursor := DllCall("CopyImage", "ptr", hIcon, "uint", 2, "int", 0, "int", 0, "uint", 0, "ptr") diff --git a/ImagePut.ahk b/ImagePut.ahk index 86bfb7bb..3f846974 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1477,7 +1477,7 @@ class ImagePut { WS_EX_TRANSPARENT := 0x20 WS_EX_DLGMODALFRAME := 0x1 - style := WS_CAPTION | WS_SYSMENU | WS_CLIPCHILDREN | WS_POPUP | WS_CLIPSIBLINGS ;| WS_SIZEBOX WS_VISIBLE | + style := WS_CAPTION | WS_SYSMENU | WS_CLIPCHILDREN | WS_POPUP | WS_CLIPSIBLINGS ;| WS_SIZEBOX WS_VISIBLE | styleEx := WS_EX_TOPMOST | WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME ;| WS_EX_STATICEDGE ; Get Bitmap width and height. @@ -1485,7 +1485,7 @@ class ImagePut { DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) ; If both dimensions exceed the screen boundaries, compare the aspect ratio of the image - ; to the aspect ratio of the screen to determine the scale factor. Default scale is 1. + ; to the aspect ratio of the screen to determine the scale factor. Default scale is 1. s := (width > A_ScreenWidth) && (width / height > A_ScreenWidth / A_ScreenHeight) ? A_ScreenWidth / width : (height > A_ScreenHeight) && (width / height <= A_ScreenWidth / A_ScreenHeight) ? A_ScreenHeight / height : 1 @@ -1539,7 +1539,7 @@ class ImagePut { , "uint", WS_VISIBLE | WS_CHILD ; dwStyle , "int", 0 , "int", 0 - , "int", w + , "int", w , "int", h , "ptr", hwnd0 ; hWndParent , "ptr", 0 ; hMenu @@ -1577,7 +1577,7 @@ if (s = 1) { , "int", 0xE200B ; Format32bppPArgb , "ptr", BitmapData) ; Contains the pointer (pBits) to the hbm. DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", BitmapData) -} +} else if ((0xFF00 & format) >> 8 = 24) { hdc2 := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") @@ -1768,7 +1768,7 @@ else { } ; Loop over all 16 system cursors and change them all to the new cursor. - SystemCursors := "32512,32513,32514,32515,32516,32640,32641,32642,32643,32644,32645,32646,32648,32649,32650,32651" + SystemCursors := "32512,32513,32514,32515,32516,32642,32643,32644,32645,32646,32648,32649,32650,32651" Loop Parse, SystemCursors, "," { ; Must copy the handle 16 times as SetSystemCursor deletes the handle 16 times. hCursor := DllCall("CopyImage", "ptr", hIcon, "uint", 2, "int", 0, "int", 0, "uint", 0, "ptr") @@ -1824,7 +1824,7 @@ else { } static put_dc(pBitmap, alpha := "") { - ; This may seem strange, but the hBitmap is selected onto the device context, + ; This may seem strange, but the hBitmap is selected onto the device context, ; and therefore cannot be deleted. In addition, the stock bitmap can never be leaked. hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") hbm := this.put_hBitmap(pBitmap, alpha) From 04f3f29ff8c8447e4d0705fc72a335b8411b8e4d Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 2 Nov 2021 17:10:27 -0400 Subject: [PATCH 092/492] ImageDestroy() --- ImagePut (for v1).ahk | 59 +++++++++++++++++++++++++++++++++++++++++-- ImagePut.ahk | 55 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index f099f85a..62bb5c97 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -104,6 +104,11 @@ ImagePutWindow(image, title := "") { return ImagePut("window", image, title) } +; A cleanup function for all images. +ImageDestroy(image) { + return ImagePut.Destroy(image) +} + ImagePut(cotype, image, p*) { return ImagePut.call(cotype, image, p*) } @@ -603,6 +608,56 @@ class ImagePut { throw Exception("Conversion from stream to " cotype " is not supported.") } + Destroy(image) { + try type := this.DontVerifyImageType(image) + catch + type := this.ImageType(image) + + if (type = "clipboard") { + if !DllCall("OpenClipboard", "ptr", A_ScriptHwnd) + throw Exception("Clipboard could not be opened.") + return DllCall("EmptyClipboard"), DllCall("CloseClipboard") + } + + if (type = "screenshot") + return DllCall("InvalidateRect", "ptr", 0, "ptr", 0, "int", 0) + + if (type = "window") + return DllCall("DestroyWindow", "ptr", image) + + if (type = "wallpaper") + return DllCall("SystemParametersInfo", "uint", SPI_SETDESKWALLPAPER := 0x14, "uint", 0, "ptr", 0, "uint", 2) + + if (type = "cursor") + return DllCall("SystemParametersInfo", "uint", SPI_SETCURSORS := 0x57, "uint", 0, "ptr", 0, "uint", 0) + + if (type = "file") + FileDelete % image + + if (type = "dc") { + if (DllCall("GetObjectType", "ptr", image, "uint") == 3) { ; OBJ_DC + hwnd := DllCall("WindowFromDC", "ptr", image, "ptr") + DllCall("ReleaseDC", "ptr", hwnd, "ptr", image) + } + + if (DllCall("GetObjectType", "ptr", image, "uint") == 10) { ; OBJ_MEMDC + DllCall("DeleteDC", "ptr", image) + } + } + + if (type = "hBitmap") + return DllCall("DeleteObject", "ptr", image) + + if (type = "hIcon") + return DllCall("DestroyIcon", "ptr", image) + + if (type = "bitmap") + return !DllCall("gdiplus\GdipDisposeImage", "ptr", image) + + if (type = "RandomAccessStream") or (type = "stream") + return !ObjRelease(image) + } + DisposeImage(pBitmap) { return DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) } @@ -1644,7 +1699,7 @@ class ImagePut { else throw Exception("Unable to create temporary image file.") ; Set the temporary image file as the new desktop wallpaper. - DllCall("SystemParametersInfo", "uint", SPI_SETDESKWALLPAPER := 20, "uint", 0, "str", buf, "uint", 2) + DllCall("SystemParametersInfo", "uint", SPI_SETDESKWALLPAPER := 0x14, "uint", 0, "str", buf, "uint", 2) ; This is a delayed delete call. #Persistent may be required on v1. DeleteFile := Func("DllCall").Bind("DeleteFile", "str", filepath) @@ -1732,7 +1787,7 @@ class ImagePut { } put_dc(pBitmap, alpha := "") { - ; This may seem strange, but the hBitmap is selected onto the device context, + ; This may seem strange, but the hBitmap is selected onto the device context, ; and therefore cannot be deleted. In addition, the stock bitmap can never be leaked. hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") hbm := this.put_hBitmap(pBitmap, alpha) diff --git a/ImagePut.ahk b/ImagePut.ahk index 3f846974..06f5afaf 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -104,6 +104,11 @@ ImagePutWindow(image, title := "") { return ImagePut("window", image, title) } +; A cleanup function for all images. +ImageDestroy(image) { + return ImagePut.Destroy(image) +} + @@ -603,6 +608,56 @@ class ImagePut { throw Error("Conversion from stream to " cotype " is not supported.") } + static Destroy(image) { + try type := this.DontVerifyImageType(image) + catch + type := this.ImageType(image) + + if (type = "clipboard") { + if !DllCall("OpenClipboard", "ptr", A_ScriptHwnd) + throw Error("Clipboard could not be opened.") + return ((_,*)=>_)(DllCall("EmptyClipboard"), DllCall("CloseClipboard")) + } + + if (type = "screenshot") + return DllCall("InvalidateRect", "ptr", 0, "ptr", 0, "int", 0) + + if (type = "window") + return DllCall("DestroyWindow", "ptr", image) + + if (type = "wallpaper") + return DllCall("SystemParametersInfo", "uint", SPI_SETDESKWALLPAPER := 0x14, "uint", 0, "ptr", 0, "uint", 2) + + if (type = "cursor") + return DllCall("SystemParametersInfo", "uint", SPI_SETCURSORS := 0x57, "uint", 0, "ptr", 0, "uint", 0) + + if (type = "file") + FileDelete image + + if (type = "dc") { + if (DllCall("GetObjectType", "ptr", image, "uint") == 3) { ; OBJ_DC + hwnd := DllCall("WindowFromDC", "ptr", image, "ptr") + DllCall("ReleaseDC", "ptr", hwnd, "ptr", image) + } + + if (DllCall("GetObjectType", "ptr", image, "uint") == 10) { ; OBJ_MEMDC + DllCall("DeleteDC", "ptr", image) + } + } + + if (type = "hBitmap") + return DllCall("DeleteObject", "ptr", image) + + if (type = "hIcon") + return DllCall("DestroyIcon", "ptr", image) + + if (type = "bitmap") + return !DllCall("gdiplus\GdipDisposeImage", "ptr", image) + + if (type = "RandomAccessStream") or (type = "stream") + return !ObjRelease(image) + } + static DisposeImage(pBitmap) { return DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) } From 3876b6be0c68f2a2f27a4a3dcab5035e45fe66ef Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 2 Nov 2021 17:12:25 -0400 Subject: [PATCH 093/492] use hexadecimal for SPI_ values --- ImagePut.ahk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index 06f5afaf..b0c48304 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1791,7 +1791,7 @@ else { else throw Error("Unable to create temporary image file.") ; Set the temporary image file as the new desktop wallpaper. - DllCall("SystemParametersInfo", "uint", SPI_SETDESKWALLPAPER := 20, "uint", 0, "str", buf, "uint", 2) + DllCall("SystemParametersInfo", "uint", SPI_SETDESKWALLPAPER := 0x14, "uint", 0, "str", buf, "uint", 2) ; This is a delayed delete call. #Persistent may be required on v1. DeleteFile := DllCall.Bind("DeleteFile", "str", filepath) From 305b4319a01bf69e530694e74acc4b1113cb7319 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 2 Nov 2021 18:52:40 -0400 Subject: [PATCH 094/492] Fix top level directory bug Was creating top level directories --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 62bb5c97..2d33dc24 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2000,7 +2000,7 @@ class ImagePut { ; Check if the entire filepath is a directory. if InStr(FileExist(filepath), "D") - directory .= "\" filename, filename := "" + directory := (directory != "") ? directory "\" filename : ".\" filename, filename := "" ; Create a new directory if needed. if (directory != "" && !InStr(FileExist(directory), "D")) diff --git a/ImagePut.ahk b/ImagePut.ahk index b0c48304..0e35f11d 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2092,7 +2092,7 @@ else { ; Check if the entire filepath is a directory. if DirExist(filepath) - directory .= "\" filename, filename := "" + directory := (directory != "") ? directory "\" filename : ".\" filename, filename := "" ; Create a new directory if needed. if (directory != "" && !DirExist(directory)) From e824c8ed30793fd45f8decfb2797959376c32d2d Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 2 Nov 2021 21:17:14 -0400 Subject: [PATCH 095/492] Use v2.0-beta.3+ --- ImagePut.ahk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index 0e35f11d..92db4be9 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -4,7 +4,7 @@ ; Date: 2021-10-07 ; Version: v1.3 -#Requires AutoHotkey v2.0-beta.1+ +#Requires AutoHotkey v2.0-beta.3+ ; Puts the image into a file format and returns a base64 encoded string. From d7e72a81f2ad77712413c9ebce07bc9b6022bada Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 4 Nov 2021 02:26:53 -0400 Subject: [PATCH 096/492] PixelFormat has size of int --- ImagePut.ahk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index 92db4be9..65c08e94 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -666,7 +666,7 @@ class ImagePut { ; Get Bitmap width, height, and format. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) - DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", pBitmap, "uint*", &format:=0) + DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", pBitmap, "int*", &format:=0) ; Are the numbers percentages? crop[3] := (crop[3] ~= "%$") ? SubStr(crop[3], 1, -1) * 0.01 * width : crop[3] @@ -717,7 +717,7 @@ class ImagePut { ; Get Bitmap width, height, and format. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) - DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", pBitmap, "uint*", &format:=0) + DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", pBitmap, "int*", &format:=0) safe_w := Ceil(width * scale) safe_h := Ceil(height * scale) @@ -1614,7 +1614,7 @@ class ImagePut { hbm := DllCall("CreateDIBSection", "ptr", hdc, "ptr", bi, "uint", 0, "ptr*", &pBits:=0, "ptr", 0, "uint", 0, "ptr") obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") - DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", pBitmap, "uint*", &format:=0) + DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", pBitmap, "int*", &format:=0) if (s = 1) { From 0434fb10abbca2565a9ffae0a599ddd7217934fe Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 6 Nov 2021 11:24:11 -0400 Subject: [PATCH 097/492] put_window parameter order --- ImagePut.ahk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index 65c08e94..86725080 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1451,7 +1451,7 @@ class ImagePut { return [x,y,w,h] } - static put_window(pBitmap, pos := "", title := "") { + static put_window(pBitmap, title := "", pos := "") { WindowProc(hwnd, uMsg, wParam, lParam) { From e0f195bea432c90472296df754b5e537e171999b Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 6 Nov 2021 11:34:39 -0400 Subject: [PATCH 098/492] filepath isn't relative --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 2d33dc24..d0693044 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -47,7 +47,7 @@ ImagePutDesktop(image) { return ImagePut("desktop", image) } -; Puts the image into a file and returns a relative filepath. +; Puts the image into a file and returns its filepath. ; filepath - Filepath + Extension | string -> *.bmp, *.gif, *.jpg, *.png, *.tiff ; quality - JPEG Quality Level | integer -> 0 - 100 ImagePutFile(image, filepath := "", quality := "") { diff --git a/ImagePut.ahk b/ImagePut.ahk index 86725080..277234a3 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -47,7 +47,7 @@ ImagePutDesktop(image) { return ImagePut("desktop", image) } -; Puts the image into a file and returns a relative filepath. +; Puts the image into a file and returns its filepath. ; filepath - Filepath + Extension | string -> *.bmp, *.gif, *.jpg, *.png, *.tiff ; quality - JPEG Quality Level | integer -> 0 - 100 ImagePutFile(image, filepath := "", quality := "") { From 8c5765760bd031af5d71bf3f7a8b6561c1847199 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 6 Nov 2021 12:01:38 -0400 Subject: [PATCH 099/492] Fix double backslashes and top level directories --- ImagePut (for v1).ahk | 11 +++++++++-- ImagePut.ahk | 11 +++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index d0693044..3593d27a 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1999,8 +1999,15 @@ class ImagePut { SplitPath % Trim(filepath),, directory, extension, filename ; Check if the entire filepath is a directory. - if InStr(FileExist(filepath), "D") - directory := (directory != "") ? directory "\" filename : ".\" filename, filename := "" + if InStr(FileExist(filepath), "D") ; If the filepath refers to a directory, + directory := (directory != "") ; then SplitPath wrongly assumes a directory to be a filename. + ? ((filename != "") + ? directory "\" filename ; Combine directory + filename. + : directory) ; Omit the final backslash if filename is empty. + : (filepath ~= "^\\") + ? "\" filename ; Root level directory. + : ".\" filename ; Script level directory. + , filename := "" ; Create a new directory if needed. if (directory != "" && !InStr(FileExist(directory), "D")) diff --git a/ImagePut.ahk b/ImagePut.ahk index 277234a3..fdd7f824 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2091,8 +2091,15 @@ else { SplitPath Trim(filepath),, &directory, &extension, &filename ; Check if the entire filepath is a directory. - if DirExist(filepath) - directory := (directory != "") ? directory "\" filename : ".\" filename, filename := "" + if DirExist(filepath) ; If the filepath refers to a directory, + directory := (directory != "") ; then SplitPath wrongly assumes a directory to be a filename. + ? ((filename != "") + ? directory "\" filename ; Combine directory + filename. + : directory) ; Omit the final backslash if filename is empty. + : (filepath ~= "^\\") + ? "\" filename ; Root level directory. + : ".\" filename ; Script level directory. + , filename := "" ; Create a new directory if needed. if (directory != "" && !DirExist(directory)) From 4dccd466b187e5d5b9bf3850869e846df9d045a2 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 6 Nov 2021 12:20:21 -0400 Subject: [PATCH 100/492] 3 spaces not 4 --- ImagePut (for v1).ahk | 10 +++++----- ImagePut.ahk | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 3593d27a..e037bae2 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2002,12 +2002,12 @@ class ImagePut { if InStr(FileExist(filepath), "D") ; If the filepath refers to a directory, directory := (directory != "") ; then SplitPath wrongly assumes a directory to be a filename. ? ((filename != "") - ? directory "\" filename ; Combine directory + filename. - : directory) ; Omit the final backslash if filename is empty. + ? directory "\" filename ; Combine directory + filename. + : directory) ; Omit the final backslash if filename is empty. : (filepath ~= "^\\") - ? "\" filename ; Root level directory. - : ".\" filename ; Script level directory. - , filename := "" + ? "\" filename ; Root level directory. + : ".\" filename ; Script level directory. + , filename := "" ; Create a new directory if needed. if (directory != "" && !InStr(FileExist(directory), "D")) diff --git a/ImagePut.ahk b/ImagePut.ahk index fdd7f824..6427f3f7 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2094,12 +2094,12 @@ else { if DirExist(filepath) ; If the filepath refers to a directory, directory := (directory != "") ; then SplitPath wrongly assumes a directory to be a filename. ? ((filename != "") - ? directory "\" filename ; Combine directory + filename. - : directory) ; Omit the final backslash if filename is empty. + ? directory "\" filename ; Combine directory + filename. + : directory) ; Omit the final backslash if filename is empty. : (filepath ~= "^\\") - ? "\" filename ; Root level directory. - : ".\" filename ; Script level directory. - , filename := "" + ? "\" filename ; Root level directory. + : ".\" filename ; Script level directory. + , filename := "" ; Create a new directory if needed. if (directory != "" && !DirExist(directory)) From e0edc05ccaedea0afa1cd6ef2dc30a5c3dc6fa29 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 6 Nov 2021 12:24:22 -0400 Subject: [PATCH 101/492] Use a while loop instead --- ImagePut (for v1).ahk | 7 ++----- ImagePut.ahk | 7 ++----- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index e037bae2..5597e23b 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2037,11 +2037,8 @@ class ImagePut { if (filename == "") { FormatTime, filename,, % "yyyy-MM-dd HH?mm?ss" filepath := directory "\" filename "." extension - if FileExist(filepath) { ; Check for collisions. - loop - filepath := directory "\" filename " (" A_Index ")." extension - until !FileExist(filepath) - } + while FileExist(filepath) ; Check for collisions. + filepath := directory "\" filename " (" A_Index ")." extension } ; Filepath is complete! diff --git a/ImagePut.ahk b/ImagePut.ahk index 6427f3f7..562daf07 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2129,11 +2129,8 @@ else { if (filename == "") { filename := FormatTime(, "yyyy-MM-dd HH?mm?ss") filepath := directory "\" filename "." extension - if FileExist(filepath) { ; Check for collisions. - loop - filepath := directory "\" filename " (" A_Index ")." extension - until !FileExist(filepath) - } + while FileExist(filepath) ; Check for collisions. + filepath := directory "\" filename " (" A_Index ")." extension } ; Filepath is complete! From 6d52d90ede1e5146142c7a8b0a91cd28ad7cb762 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 6 Nov 2021 17:05:59 -0400 Subject: [PATCH 102/492] Use BiCubic --- ImagePut.ahk | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index 562daf07..69b9a65f 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1616,7 +1616,6 @@ class ImagePut { DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", pBitmap, "int*", &format:=0) - if (s = 1) { ; Transfer data from source pBitmap to an hBitmap manually. Rect := Buffer(16, 0) ; sizeof(Rect) = 16 @@ -1681,7 +1680,7 @@ else { ; Set settings in graphics context. DllCall("gdiplus\GdipSetPixelOffsetMode", "ptr", pGraphics, "int", 2) ; Half pixel offset. DllCall("gdiplus\GdipSetCompositingMode", "ptr", pGraphics, "int", 1) ; Overwrite/SourceCopy. - DllCall("gdiplus\GdipSetInterpolationMode", "ptr", pGraphics, "int", 6) ; HighQualityBicubic + DllCall("gdiplus\GdipSetInterpolationMode", "ptr", pGraphics, "int", 7) ; HighQualityBicubic ; Draw Image. DllCall("gdiplus\GdipCreateImageAttributes", "ptr*", &ImageAttr:=0) From a08b715d1235ff487c23dcc90ed80712b5a3205f Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 6 Nov 2021 17:06:51 -0400 Subject: [PATCH 103/492] Tentative support for PDF files --- ImagePut (for v1).ahk | 63 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 5597e23b..fef300d1 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -370,8 +370,12 @@ class ImagePut { return "url" ; A "file" is stored on the disk or network. - if FileExist(image) + if FileExist(image) { + if image ~= ".pdf$" + return "pdf" + return "file" + } if (image ~= "^-?\d+$") { SysGet MonitorGetCount, MonitorCount ; A non-zero "monitor" number identifies each display uniquely; and 0 refers to the entire virtual screen. @@ -453,6 +457,9 @@ class ImagePut { if (type = "url") return this.from_url(image) + if (type = "pdf") + return this.from_pdf(image) + if (type = "file") return this.from_file(image) @@ -1045,6 +1052,60 @@ class ImagePut { return pStream } + from_pdf(image, page := 0) { + ; Create the "Windows.Data.Pdf.PdfDocument" class using IPdfDocumentStatics. + DllCall("combase\WindowsCreateString", "wstr", "Windows.Data.Pdf.PdfDocument", "uint", 28, "ptr*", hString:=0, "uint") + DllCall("ole32\CLSIDFromString", "wstr", "{433A0B5F-C007-4788-90F2-08143D922599}", "ptr", &CLSID := VarSetCapacity(CLSID, 16), "uint") + DllCall("combase\RoGetActivationFactory", "ptr", hString, "ptr", &CLSID, "ptr*", PdfDocumentStatics:=0, "uint") + DllCall("combase\WindowsDeleteString", "ptr", hString, "uint") + + ; Open a file as a RandomAccessStream. + DllCall("ole32\CLSIDFromString", "wstr", "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}", "ptr", &CLSID := VarSetCapacity(CLSID, 16), "uint") + DllCall("ShCore\CreateRandomAccessStreamOnFile", "wstr", image, "uint", Read := 0, "ptr", &CLSID, "ptr*", IRandomAccessStream, "uint") + + ; Create the PDF document. + DllCall(PdfDocument_LoadFromStreamAsync := NumGet(NumGet(PdfDocumentStatics+0)+8*A_PtrSize), "ptr", PdfDocumentStatics, "ptr", IRandomAccessStream, "ptr*", PdfDocument) + this.WaitForAsync(PdfDocument) + + ; Get Page + DllCall(NumGet(NumGet(PdfDocument+0)+6*A_PtrSize), "ptr", PdfDocument, "uint", page, "ptr*", PdfPage) ; GetPage + + ; Render the page to an output stream. + DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "uint", true, "ptr*", IStream) + DllCall("ole32\CLSIDFromString", "wstr", "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}", "ptr", &CLSID := VarSetCapacity(CLSID, 16), "uint") + DllCall("ShCore\CreateRandomAccessStreamOverStream", "ptr", IStream, "uint", BSOS_DEFAULT := 0, "ptr", &CLSID, "ptr*", IRandomAccessStreamOut) + DllCall(NumGet(NumGet(PdfPage+0)+6*A_PtrSize), "ptr", PdfPage, "ptr", IRandomAccessStreamOut, "ptr*", asyncInfo) ; RenderToStreamAsync + this.WaitForAsync(asyncInfo) + + DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", IStream, "ptr*", pBitmap:=0) + + ObjRelease(IRandomAccessStreamOut) + ObjRelease(IStream) + ObjRelease(PdfPage) + ObjRelease(PdfDocument) + ObjRelease(IRandomAccessStream) + ObjRelease(PdfDocumentStatics) + return pBitmap + } + + WaitForAsync(ByRef Object) { + AsyncInfo := ComObjQuery(Object, IAsyncInfo := "{00000036-0000-0000-C000-000000000046}") + while !DllCall(IAsyncInfo_Status := NumGet(NumGet(AsyncInfo+0)+7*A_PtrSize), "ptr", AsyncInfo, "uint*", status:=0) + and (status = 0) + Sleep 10 + + if (status != 1) { + DllCall(IAsyncInfo_ErrorCode := NumGet(NumGet(AsyncInfo+0)+8*A_PtrSize), "ptr", AsyncInfo, "uint*", ErrorCode:=0) + throw Exception("AsyncInfo status error: " ErrorCode) + } + + ObjRelease(AsyncInfo) + + DllCall(NumGet(NumGet(Object+0)+8*A_PtrSize), "ptr", Object, "ptr*", ObjectResult) ; GetResults + ObjRelease(Object) + Object := ObjectResult + } + from_monitor(image) { if (image > 0) { SysGet _, Monitor, image From cf3c713813af2da55f86001895729e1e341b3d47 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 21 Nov 2021 11:19:46 -0500 Subject: [PATCH 104/492] Support PDF page numbers ImagePutWindow({pdf: "doc.pdf", index:2}) --- ImagePut (for v1).ahk | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index fef300d1..a91539ef 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -143,6 +143,8 @@ class ImagePut { ForceDecodeImagePixels := image.ForceDecodeImagePixels ForcePushImageToMemory := image.ForcePushImageToMemory + index := image.index + ; Dereference the image unknown. if ObjHasKey(image, "image") image := image.image @@ -183,7 +185,7 @@ class ImagePut { ; Fallback to GDI+ bitmap as the intermediate. else { ; Make a copy of the image as a pBitmap. - pBitmap := this.ToBitmap(type, image) + pBitmap := this.ToBitmap(type, image, index) ; Load the image pixels to the bitmap buffer. ; This increases memory usage but prevents any changes to the pixels, @@ -428,7 +430,7 @@ class ImagePut { throw Exception("Image type could not be identified.") } - ToBitmap(type, image) { + ToBitmap(type, image, index := "") { if (type = "clipboard") return this.from_clipboard() @@ -458,7 +460,7 @@ class ImagePut { return this.from_url(image) if (type = "pdf") - return this.from_pdf(image) + return this.from_pdf(image, index) if (type = "file") return this.from_file(image) @@ -1052,7 +1054,9 @@ class ImagePut { return pStream } - from_pdf(image, page := 0) { + from_pdf(image, page) { + page := (page) ? page - 1 : 0 ; Zero indexed. + ; Create the "Windows.Data.Pdf.PdfDocument" class using IPdfDocumentStatics. DllCall("combase\WindowsCreateString", "wstr", "Windows.Data.Pdf.PdfDocument", "uint", 28, "ptr*", hString:=0, "uint") DllCall("ole32\CLSIDFromString", "wstr", "{433A0B5F-C007-4788-90F2-08143D922599}", "ptr", &CLSID := VarSetCapacity(CLSID, 16), "uint") From a5d68180653b1b0ecc8aad53ff8b76da8adc9795 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 24 Nov 2021 23:33:06 -0500 Subject: [PATCH 105/492] Add pdf to DontVerifyImageType --- ImagePut (for v1).ahk | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index a91539ef..2c95fe02 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -275,6 +275,11 @@ class ImagePut { return "file" } + if ObjHasKey(image, "pdf") { + image := image.pdf + return "pdf" + } + if ObjHasKey(image, "monitor") { image := image.monitor return "monitor" From 281c836f4ff894c52c607ca286cfd9a2d9edbdb8 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 1 Dec 2021 01:28:21 -0500 Subject: [PATCH 106/492] comments --- ImagePut (for v1).ahk | 6 +++--- ImagePut.ahk | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 2c95fe02..745e4c2d 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2069,11 +2069,11 @@ class ImagePut { SplitPath % Trim(filepath),, directory, extension, filename ; Check if the entire filepath is a directory. - if InStr(FileExist(filepath), "D") ; If the filepath refers to a directory, - directory := (directory != "") ; then SplitPath wrongly assumes a directory to be a filename. + if InStr(FileExist(filepath), "D") ; If the filepath refers to a directory, + directory := (directory != "") ; then SplitPath wrongly assumes a directory to be a filename. ? ((filename != "") ? directory "\" filename ; Combine directory + filename. - : directory) ; Omit the final backslash if filename is empty. + : directory) ; Do nothing. : (filepath ~= "^\\") ? "\" filename ; Root level directory. : ".\" filename ; Script level directory. diff --git a/ImagePut.ahk b/ImagePut.ahk index 69b9a65f..f37538d4 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2090,11 +2090,11 @@ else { SplitPath Trim(filepath),, &directory, &extension, &filename ; Check if the entire filepath is a directory. - if DirExist(filepath) ; If the filepath refers to a directory, - directory := (directory != "") ; then SplitPath wrongly assumes a directory to be a filename. + if DirExist(filepath) ; If the filepath refers to a directory, + directory := (directory != "") ; then SplitPath wrongly assumes a directory to be a filename. ? ((filename != "") ? directory "\" filename ; Combine directory + filename. - : directory) ; Omit the final backslash if filename is empty. + : directory) ; Do nothing. : (filepath ~= "^\\") ? "\" filename ; Root level directory. : ".\" filename ; Script level directory. From 3f14674d08440717c869839eff0e13c192ecaccb Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 8 Dec 2021 23:37:43 -0500 Subject: [PATCH 107/492] Refactor BitmapCrop & BitmapScale --- ImagePut (for v1).ahk | 26 ++++++++++++++------------ ImagePut.ahk | 26 ++++++++++++++------------ 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 745e4c2d..40196b53 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -676,7 +676,13 @@ class ImagePut { return DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) } - BitmapCrop(ByRef pBitmap, crop, dispose := true) { + BitmapCrop(ByRef pBitmap, crop) { + pBitmapCrop := this.BitmapCropNew(pBitmap, crop) + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + pBitmap := pBitmapCrop + } + + BitmapCropNew(pBitmap, crop) { ; Get Bitmap width, height, and format. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) @@ -719,15 +725,16 @@ class ImagePut { , "ptr", pBitmap , "ptr*", pBitmapCrop:=0) - if (dispose) { - DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) - pBitmap := pBitmapCrop - } - return pBitmapCrop } - BitmapScale(ByRef pBitmap, scale, dispose := true) { + BitmapScale(ByRef pBitmap, scale) { + pBitmapScale := this.BitmapScaleNew(pBitmap, scale) + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + pBitmap := pBitmapScale + } + + BitmapScaleNew(pBitmap, scale) { ; Get Bitmap width, height, and format. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) @@ -763,11 +770,6 @@ class ImagePut { ; Clean up the graphics context. DllCall("gdiplus\GdipDeleteGraphics", "ptr", pGraphics) - if (dispose) { - DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) - pBitmap := pBitmapScale - } - return pBitmapScale } diff --git a/ImagePut.ahk b/ImagePut.ahk index f37538d4..9c72e145 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -662,7 +662,13 @@ class ImagePut { return DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) } - static BitmapCrop(&pBitmap, crop, dispose := true) { + static BitmapCrop(&pBitmap, crop) { + pBitmapCrop := this.BitmapCropNew(pBitmap, crop) + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + pBitmap := pBitmapCrop + } + + static BitmapCropNew(pBitmap, crop) { ; Get Bitmap width, height, and format. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) @@ -705,15 +711,16 @@ class ImagePut { , "ptr", pBitmap , "ptr*", &pBitmapCrop:=0) - if (dispose) { - DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) - pBitmap := pBitmapCrop - } - return pBitmapCrop } - static BitmapScale(&pBitmap, scale, dispose := true) { + static BitmapScale(&pBitmap, scale) { + pBitmapScale := this.BitmapScaleNew(pBitmap, scale) + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + pBitmap := pBitmapScale + } + + static BitmapScaleNew(pBitmap, scale) { ; Get Bitmap width, height, and format. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) @@ -749,11 +756,6 @@ class ImagePut { ; Clean up the graphics context. DllCall("gdiplus\GdipDeleteGraphics", "ptr", pGraphics) - if (dispose) { - DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) - pBitmap := pBitmapScale - } - return pBitmapScale } From 2abb4953d6bdce3ea98403fc83b8a37bf9a0b17b Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 9 Dec 2021 00:43:30 -0500 Subject: [PATCH 108/492] Add scale:[width, height] --- ImagePut (for v1).ahk | 57 ++++++++++++++++++++----------------------- ImagePut.ahk | 55 ++++++++++++++++++++--------------------- 2 files changed, 54 insertions(+), 58 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 40196b53..9866cfaf 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -130,30 +130,19 @@ class ImagePut { ; p* - Additional Parameters | variadic -> Extra parameters found in BitmapToCoimage(). call(cotype, image, p*) { - crop := scale := false - ; Extract parameters. if IsObject(image) { - crop := IsObject(image.crop) - && image.crop[1] ~= "^-?\d+(\.\d*)?%?$" && image.crop[2] ~= "^-?\d+(\.\d*)?%?$" - && image.crop[3] ~= "^-?\d+(\.\d*)?%?$" && image.crop[4] ~= "^-?\d+(\.\d*)?%?$" - ? image.crop : false - scale := image.scale != 1 && image.scale ~= "^\d+(\.\d+)?$" - ? image.scale : false - ForceDecodeImagePixels := image.ForceDecodeImagePixels - ForcePushImageToMemory := image.ForcePushImageToMemory - - index := image.index + index := ObjHasKey(image, "index") ? image.index : "" + crop := ObjHasKey(image, "crop") ? image.crop : false + scale := ObjHasKey(image, "scale") ? image.scale : false + ForceDecodeImagePixels := this.ForceDecodeImagePixels ? true : image.ForceDecodeImagePixels + ForcePushImageToMemory := this.ForcePushImageToMemory ? true : image.ForcePushImageToMemory ; Dereference the image unknown. if ObjHasKey(image, "image") image := image.image } - ForceDecodeImagePixels := this.ForceDecodeImagePixels ? true : ForceDecodeImagePixels ? true : false - ForcePushImageToMemory := this.ForcePushImageToMemory ? true : ForcePushImageToMemory ? true : false - - ; Start! this.gdiplusStartup() @@ -677,12 +666,11 @@ class ImagePut { } BitmapCrop(ByRef pBitmap, crop) { - pBitmapCrop := this.BitmapCropNew(pBitmap, crop) - DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) - pBitmap := pBitmapCrop - } + if not (IsObject(crop) + && crop[1] ~= "^-?\d+(\.\d*)?%?$" && crop[2] ~= "^-?\d+(\.\d*)?%?$" + && crop[3] ~= "^-?\d+(\.\d*)?%?$" && crop[4] ~= "^-?\d+(\.\d*)?%?$") + throw Exception("Invalid crop.") - BitmapCropNew(pBitmap, crop) { ; Get Bitmap width, height, and format. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) @@ -725,23 +713,31 @@ class ImagePut { , "ptr", pBitmap , "ptr*", pBitmapCrop:=0) - return pBitmapCrop + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + + return pBitmap := pBitmapCrop } BitmapScale(ByRef pBitmap, scale) { - pBitmapScale := this.BitmapScaleNew(pBitmap, scale) - DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) - pBitmap := pBitmapScale - } + if not (IsObject(scale) && (scale[1] ~= "^\d+$") && (scale[2] ~= "^\d+$") || (scale ~= "^\d+(\.\d+)?$")) + throw Exception("Invalid scale.") - BitmapScaleNew(pBitmap, scale) { ; Get Bitmap width, height, and format. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", pBitmap, "int*", format:=0) - safe_w := Ceil(width * scale) - safe_h := Ceil(height * scale) + if IsObject(scale) { + safe_w := Round(scale[1]) + safe_h := Round(scale[2]) + } else { + safe_w := Ceil(width * scale) + safe_h := Ceil(height * scale) + } + + ; Avoid drawing if no changes detected. + if (safe_w = width && safe_h = height) + return pBitmap ; Create a new bitmap and get the graphics context. DllCall("gdiplus\GdipCreateBitmapFromScan0" @@ -769,8 +765,9 @@ class ImagePut { ; Clean up the graphics context. DllCall("gdiplus\GdipDeleteGraphics", "ptr", pGraphics) + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) - return pBitmapScale + return pBitmap := pBitmapScale } is_url(url) { diff --git a/ImagePut.ahk b/ImagePut.ahk index 9c72e145..10dbc99f 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -130,28 +130,19 @@ class ImagePut { ; p* - Additional Parameters | variadic -> Extra parameters found in BitmapToCoimage(). static call(cotype, image, p*) { - crop := scale := false - ; Extract parameters. if IsObject(image) { - crop := image.HasOwnProp("crop") && IsObject(image.crop) - && image.crop[1] ~= "^-?\d+(\.\d*)?%?$" && image.crop[2] ~= "^-?\d+(\.\d*)?%?$" - && image.crop[3] ~= "^-?\d+(\.\d*)?%?$" && image.crop[4] ~= "^-?\d+(\.\d*)?%?$" - ? image.crop : false - scale := image.HasOwnProp("scale") && image.scale != 1 && image.scale ~= "^\d+(\.\d+)?$" - ? image.scale : false - ForceDecodeImagePixels := image.HasOwnProp("ForceDecodeImagePixels") ? image.ForceDecodeImagePixels : false - ForcePushImageToMemory := image.HasOwnProp("ForcePushImageToMemory") ? image.ForcePushImageToMemory : false + index := ObjHasOwnProp(image, "index") ? image.index : "" + crop := ObjHasOwnProp(image, "crop") ? image.crop : false + scale := ObjHasOwnProp(image, "scale") ? image.scale : false + ForceDecodeImagePixels := this.ForceDecodeImagePixels ? true : ObjHasOwnProp(image, "ForceDecodeImagePixels") ? image.ForceDecodeImagePixels : false + ForcePushImageToMemory := this.ForcePushImageToMemory ? true : ObjHasOwnProp(image, "ForcePushImageToMemory") ? image.ForcePushImageToMemory : false ; Dereference the image unknown. if ObjHasOwnProp(image, "image") image := image.image } - ForceDecodeImagePixels := this.ForceDecodeImagePixels ? true : IsSet(ForceDecodeImagePixels) ? true : false - ForcePushImageToMemory := this.ForcePushImageToMemory ? true : IsSet(ForcePushImageToMemory) ? true : false - - ; Start! this.gdiplusStartup() @@ -663,12 +654,11 @@ class ImagePut { } static BitmapCrop(&pBitmap, crop) { - pBitmapCrop := this.BitmapCropNew(pBitmap, crop) - DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) - pBitmap := pBitmapCrop - } + if not (IsObject(crop) + && crop[1] ~= "^-?\d+(\.\d*)?%?$" && crop[2] ~= "^-?\d+(\.\d*)?%?$" + && crop[3] ~= "^-?\d+(\.\d*)?%?$" && crop[4] ~= "^-?\d+(\.\d*)?%?$") + throw Error("Invalid crop.") - static BitmapCropNew(pBitmap, crop) { ; Get Bitmap width, height, and format. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) @@ -711,23 +701,31 @@ class ImagePut { , "ptr", pBitmap , "ptr*", &pBitmapCrop:=0) - return pBitmapCrop + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + + return pBitmap := pBitmapCrop } static BitmapScale(&pBitmap, scale) { - pBitmapScale := this.BitmapScaleNew(pBitmap, scale) - DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) - pBitmap := pBitmapScale - } + if not (IsObject(scale) && (scale[1] ~= "^\d+$") && (scale[2] ~= "^\d+$") || (scale ~= "^\d+(\.\d+)?$")) + throw Error("Invalid scale.") - static BitmapScaleNew(pBitmap, scale) { ; Get Bitmap width, height, and format. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", pBitmap, "int*", &format:=0) - safe_w := Ceil(width * scale) - safe_h := Ceil(height * scale) + if IsObject(scale) { + safe_w := Round(scale[1]) + safe_h := Round(scale[2]) + } else { + safe_w := Ceil(width * scale) + safe_h := Ceil(height * scale) + } + + ; Avoid drawing if no changes detected. + if (safe_w = width && safe_h = height) + return pBitmap ; Create a new bitmap and get the graphics context. DllCall("gdiplus\GdipCreateBitmapFromScan0" @@ -755,8 +753,9 @@ class ImagePut { ; Clean up the graphics context. DllCall("gdiplus\GdipDeleteGraphics", "ptr", pGraphics) + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) - return pBitmapScale + return pBitmap := pBitmapScale } static is_url(url) { From c6403a2f304f8fb068c9901652d96ffe523f2d08 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 9 Dec 2021 01:28:13 -0500 Subject: [PATCH 109/492] Improve code density --- ImagePut (for v1).ahk | 38 ++++++++++++++++---------------------- ImagePut.ahk | 42 ++++++++++++++++++------------------------ 2 files changed, 34 insertions(+), 46 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 9866cfaf..e7e55960 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -141,6 +141,11 @@ class ImagePut { ; Dereference the image unknown. if ObjHasKey(image, "image") image := image.image + + } else { + index := crop := scale := false + ForceDecodeImagePixels := this.ForceDecodeImagePixels + ForcePushImageToMemory := this.ForcePushImageToMemory } ; Start! @@ -151,13 +156,13 @@ class ImagePut { catch type := this.ImageType(image) - ; Check if a stream can be used as an intermediate. + ; #1 - Stream intermediate. if not ForceDecodeImagePixels and not crop and not scale and (type ~= "^(?i:url|file|stream|RandomAccessStream|hex|base64)$") and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64)$") and (p[1] = "") { ; For now, disallow any specification of extensions. - ; Convert to a stream intermediate then to the output coimage. + ; Convert via stream intermediate. pStream := this.ToStream(type, image) coimage := this.StreamToCoimage(cotype, pStream, p*) @@ -171,28 +176,17 @@ class ImagePut { return coimage } - ; Fallback to GDI+ bitmap as the intermediate. + ; #2 - Fallback to GDI+ bitmap as the intermediate. else { - ; Make a copy of the image as a pBitmap. - pBitmap := this.ToBitmap(type, image, index) - - ; Load the image pixels to the bitmap buffer. - ; This increases memory usage but prevents any changes to the pixels, - ; and bypasses any copy-on-write and copy on LockBits read behavior. - ; This must be called immediately after the pBitmap is created - ; or it will fail without throwing any errors. - if (ForcePushImageToMemory) - DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmap) + ; GdipImageForceValidation must be called immediately or it fails without any errors. + ; It load the image pixels to the bitmap buffer, increasing memory usage and prevents + ; changes to the pixels while bypassing any copy-on-write and copy on LockBits(read) behavior. - ; Crop the image. - if (crop) - this.BitmapCrop(pBitmap, crop) - - ; Scale the image. - if (scale) - this.BitmapScale(pBitmap, scale) - - ; Put the pBitmap to wherever the cotype specifies. + ; Convert via GDI+ bitmap intermediate. + pBitmap := this.ToBitmap(type, image, index) + (ForcePushImageToMemory) ? DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmap) : {} + (crop) ? this.BitmapCrop(pBitmap, crop) : {} + (scale) ? this.BitmapScale(pBitmap, scale) : {} coimage := this.BitmapToCoimage(cotype, pBitmap, p*) ; Clean up the pBitmap copy. Export raw pointers if requested. diff --git a/ImagePut.ahk b/ImagePut.ahk index 10dbc99f..f6076334 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -141,6 +141,11 @@ class ImagePut { ; Dereference the image unknown. if ObjHasOwnProp(image, "image") image := image.image + + } else { + index := crop := scale := false + ForceDecodeImagePixels := this.ForceDecodeImagePixels + ForcePushImageToMemory := this.ForcePushImageToMemory } ; Start! @@ -151,13 +156,13 @@ class ImagePut { catch type := this.ImageType(image) - ; Check if a stream can be used as an intermediate. + ; #1 - Stream intermediate. if not ForceDecodeImagePixels and not crop and not scale and (type ~= "^(?i:url|file|stream|RandomAccessStream|hex|base64)$") and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64)$") and (!p.Has(1) || p[1] == "") { ; For now, disallow any specification of extensions. - ; Convert to a stream intermediate then to the output coimage. + ; Convert via stream intermediate. pStream := this.ToStream(type, image) coimage := this.StreamToCoimage(cotype, pStream, p*) @@ -171,28 +176,17 @@ class ImagePut { return coimage } - ; Fallback to GDI+ bitmap as the intermediate. + ; #2 - Fallback to GDI+ bitmap as the intermediate. else { - ; Make a copy of the image as a pBitmap. - pBitmap := this.ToBitmap(type, image) - - ; Load the image pixels to the bitmap buffer. - ; This increases memory usage but prevents any changes to the pixels, - ; and bypasses any copy-on-write and copy on LockBits read behavior. - ; This must be called immediately after the pBitmap is created - ; or it will fail without throwing any errors. - if (ForcePushImageToMemory) - DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmap) - - ; Crop the image. - if (crop) - this.BitmapCrop(&pBitmap, crop) - - ; Scale the image. - if (scale) - this.BitmapScale(&pBitmap, scale) - - ; Put the pBitmap to wherever the cotype specifies. + ; GdipImageForceValidation must be called immediately or it fails without any errors. + ; It load the image pixels to the bitmap buffer, increasing memory usage and prevents + ; changes to the pixels while bypassing any copy-on-write and copy on LockBits(read) behavior. + + ; Convert via GDI+ bitmap intermediate. + pBitmap := this.ToBitmap(type, image, index) + (ForcePushImageToMemory) ? DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmap) : {} + (crop) ? this.BitmapCrop(&pBitmap, crop) : {} + (scale) ? this.BitmapScale(&pBitmap, scale) : {} coimage := this.BitmapToCoimage(cotype, pBitmap, p*) ; Clean up the pBitmap copy. Export raw pointers if requested. @@ -415,7 +409,7 @@ class ImagePut { throw Error("Image type could not be identified.") } - static ToBitmap(type, image) { + static ToBitmap(type, image, index := "") { if (type = "clipboard") return this.from_clipboard() From c02159d35df99abcbb1c67fd08261a5e4cceba8e Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 9 Dec 2021 11:12:53 -0500 Subject: [PATCH 110/492] Use semantic versioning --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index e7e55960..a8a63b4e 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2,7 +2,7 @@ ; License: MIT License ; Author: Edison Hua (iseahound) ; Date: 2021-10-07 -; Version: v1.3 +; Version: 1.3.0 #Requires AutoHotkey v1.1.33+ diff --git a/ImagePut.ahk b/ImagePut.ahk index f6076334..6c92a35f 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2,7 +2,7 @@ ; License: MIT License ; Author: Edison Hua (iseahound) ; Date: 2021-10-07 -; Version: v1.3 +; Version: 1.3.0 #Requires AutoHotkey v2.0-beta.3+ From cb323eadf2388fea10006acccf090e86eb1d2572 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 10 Dec 2021 11:18:35 -0500 Subject: [PATCH 111/492] Passing one side length to scale --- ImagePut (for v1).ahk | 6 +++--- ImagePut.ahk | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index a8a63b4e..7dbcfe89 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -713,7 +713,7 @@ class ImagePut { } BitmapScale(ByRef pBitmap, scale) { - if not (IsObject(scale) && (scale[1] ~= "^\d+$") && (scale[2] ~= "^\d+$") || (scale ~= "^\d+(\.\d+)?$")) + if not (IsObject(scale) && ((scale[1] ~= "^\d+$") || (scale[2] ~= "^\d+$")) || (scale ~= "^\d+(\.\d+)?$")) throw Exception("Invalid scale.") ; Get Bitmap width, height, and format. @@ -722,8 +722,8 @@ class ImagePut { DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", pBitmap, "int*", format:=0) if IsObject(scale) { - safe_w := Round(scale[1]) - safe_h := Round(scale[2]) + safe_w := (scale[1] ~= "^\d+$") ? scale[1] : Round(width / height * scale[2]) + safe_h := (scale[2] ~= "^\d+$") ? scale[2] : Round(height / width * scale[1]) } else { safe_w := Ceil(width * scale) safe_h := Ceil(height * scale) diff --git a/ImagePut.ahk b/ImagePut.ahk index 6c92a35f..304fe06d 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -701,7 +701,7 @@ class ImagePut { } static BitmapScale(&pBitmap, scale) { - if not (IsObject(scale) && (scale[1] ~= "^\d+$") && (scale[2] ~= "^\d+$") || (scale ~= "^\d+(\.\d+)?$")) + if not (IsObject(scale) && ((scale[1] ~= "^\d+$") || (scale[2] ~= "^\d+$")) || (scale ~= "^\d+(\.\d+)?$")) throw Error("Invalid scale.") ; Get Bitmap width, height, and format. @@ -710,8 +710,8 @@ class ImagePut { DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", pBitmap, "int*", &format:=0) if IsObject(scale) { - safe_w := Round(scale[1]) - safe_h := Round(scale[2]) + safe_w := (scale[1] ~= "^\d+$") ? scale[1] : Round(width / height * scale[2]) + safe_h := (scale[2] ~= "^\d+$") ? scale[2] : Round(height / width * scale[1]) } else { safe_w := Ceil(width * scale) safe_h := Ceil(height * scale) From 507786dda33eab5307bd548ed96b723c3d426e1f Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 11 Dec 2021 00:03:48 -0500 Subject: [PATCH 112/492] standardize "pass" statement --- ImagePut (for v1).ahk | 6 +++--- ImagePut.ahk | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 7dbcfe89..113fcb94 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -132,7 +132,7 @@ class ImagePut { ; Extract parameters. if IsObject(image) { - index := ObjHasKey(image, "index") ? image.index : "" + index := ObjHasKey(image, "index") ? image.index : false crop := ObjHasKey(image, "crop") ? image.crop : false scale := ObjHasKey(image, "scale") ? image.scale : false ForceDecodeImagePixels := this.ForceDecodeImagePixels ? true : image.ForceDecodeImagePixels @@ -1783,8 +1783,8 @@ class ImagePut { VarSetCapacity(ii, 8+3*A_PtrSize) ; sizeof(ICONINFO) = 20, 32 DllCall("GetIconInfo", "ptr", hIcon, "ptr", &ii) ; Fill the ICONINFO structure. NumPut(false, ii, 0, "uint") ; true/false are icon/cursor respectively. - (xHotspot != "") ? NumPut(xHotspot, ii, 4, "uint") : "" ; Set the xHotspot value. (Default: center point) - (yHotspot != "") ? NumPut(yHotspot, ii, 8, "uint") : "" ; Set the yHotspot value. (Default: center point) + (xHotspot != "") ? NumPut(xHotspot, ii, 4, "uint") : {} ; Set the xHotspot value. (Default: center point) + (yHotspot != "") ? NumPut(yHotspot, ii, 8, "uint") : {} ; Set the yHotspot value. (Default: center point) DllCall("DestroyIcon", "ptr", hIcon) ; Destroy the icon after getting the ICONINFO structure. hIcon := DllCall("CreateIconIndirect", "ptr", &ii, "ptr") ; Create a new cursor using ICONINFO. diff --git a/ImagePut.ahk b/ImagePut.ahk index 304fe06d..04b8bc79 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -132,7 +132,7 @@ class ImagePut { ; Extract parameters. if IsObject(image) { - index := ObjHasOwnProp(image, "index") ? image.index : "" + index := ObjHasOwnProp(image, "index") ? image.index : false crop := ObjHasOwnProp(image, "crop") ? image.crop : false scale := ObjHasOwnProp(image, "scale") ? image.scale : false ForceDecodeImagePixels := this.ForceDecodeImagePixels ? true : ObjHasOwnProp(image, "ForceDecodeImagePixels") ? image.ForceDecodeImagePixels : false @@ -1806,8 +1806,8 @@ else { ii := Buffer(8+3*A_PtrSize) ; sizeof(ICONINFO) = 20, 32 DllCall("GetIconInfo", "ptr", hIcon, "ptr", ii) ; Fill the ICONINFO structure. NumPut("uint", false, ii, 0) ; true/false are icon/cursor respectively. - (xHotspot != "") ? NumPut("uint", xHotspot, ii, 4) : "" ; Set the xHotspot value. (Default: center point) - (yHotspot != "") ? NumPut("uint", yHotspot, ii, 8) : "" ; Set the yHotspot value. (Default: center point) + (xHotspot != "") ? NumPut("uint", xHotspot, ii, 4) : {} ; Set the xHotspot value. (Default: center point) + (yHotspot != "") ? NumPut("uint", yHotspot, ii, 8) : {} ; Set the yHotspot value. (Default: center point) DllCall("DestroyIcon", "ptr", hIcon) ; Destroy the icon after getting the ICONINFO structure. hIcon := DllCall("CreateIconIndirect", "ptr", ii, "ptr") ; Create a new cursor using ICONINFO. From 3640d8d2e60d88e46e9aaa13416e7fa4ff9b0157 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 11 Dec 2021 12:18:56 -0500 Subject: [PATCH 113/492] Reduce parameter length --- ImagePut (for v1).ahk | 19 ++++++++----------- ImagePut.ahk | 19 ++++++++----------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 113fcb94..aba7dbfd 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -116,11 +116,8 @@ ImagePut(cotype, image, p*) { class ImagePut { - ; If true the conversion will always go through a GDI+ Bitmap and the original file encoding will be lost. - static ForceDecodeImagePixels := false - - ; If true the pBitmap will always be filled with image data instead of referencing it and copying when needed. - static ForcePushImageToMemory := false + static decode := false ; Forces conversion using a bitmap. The original file encoding will be lost. + static validate := false ; Always copies image data into memory instead of passing references. ; ImagePut() - Puts an image from anywhere to anywhere. ; cotype - Output Type | string -> Case Insensitive. Read documentation. @@ -135,8 +132,8 @@ class ImagePut { index := ObjHasKey(image, "index") ? image.index : false crop := ObjHasKey(image, "crop") ? image.crop : false scale := ObjHasKey(image, "scale") ? image.scale : false - ForceDecodeImagePixels := this.ForceDecodeImagePixels ? true : image.ForceDecodeImagePixels - ForcePushImageToMemory := this.ForcePushImageToMemory ? true : image.ForcePushImageToMemory + decode := ObjHasKey(image, "decode") ? image.decode : this.decode + validate := ObjHasKey(image, "validate") ? image.validate : this.validate ; Dereference the image unknown. if ObjHasKey(image, "image") @@ -144,8 +141,8 @@ class ImagePut { } else { index := crop := scale := false - ForceDecodeImagePixels := this.ForceDecodeImagePixels - ForcePushImageToMemory := this.ForcePushImageToMemory + decode := this.decode + validate := this.validate } ; Start! @@ -157,7 +154,7 @@ class ImagePut { type := this.ImageType(image) ; #1 - Stream intermediate. - if not ForceDecodeImagePixels and not crop and not scale + if not decode and not crop and not scale and (type ~= "^(?i:url|file|stream|RandomAccessStream|hex|base64)$") and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64)$") and (p[1] = "") { ; For now, disallow any specification of extensions. @@ -184,7 +181,7 @@ class ImagePut { ; Convert via GDI+ bitmap intermediate. pBitmap := this.ToBitmap(type, image, index) - (ForcePushImageToMemory) ? DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmap) : {} + (validate) ? DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmap) : {} (crop) ? this.BitmapCrop(pBitmap, crop) : {} (scale) ? this.BitmapScale(pBitmap, scale) : {} coimage := this.BitmapToCoimage(cotype, pBitmap, p*) diff --git a/ImagePut.ahk b/ImagePut.ahk index 04b8bc79..e73a0d7c 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -116,11 +116,8 @@ ImageDestroy(image) { class ImagePut { - ; If true the conversion will always go through a GDI+ Bitmap and the original file encoding will be lost. - static ForceDecodeImagePixels := false - - ; If true the pBitmap will always be filled with image data instead of referencing it and copying when needed. - static ForcePushImageToMemory := false + static decode := false ; Forces conversion using a bitmap. The original file encoding will be lost. + static validate := false ; Always copies image data into memory instead of passing references. ; ImagePut() - Puts an image from anywhere to anywhere. ; cotype - Output Type | string -> Case Insensitive. Read documentation. @@ -135,8 +132,8 @@ class ImagePut { index := ObjHasOwnProp(image, "index") ? image.index : false crop := ObjHasOwnProp(image, "crop") ? image.crop : false scale := ObjHasOwnProp(image, "scale") ? image.scale : false - ForceDecodeImagePixels := this.ForceDecodeImagePixels ? true : ObjHasOwnProp(image, "ForceDecodeImagePixels") ? image.ForceDecodeImagePixels : false - ForcePushImageToMemory := this.ForcePushImageToMemory ? true : ObjHasOwnProp(image, "ForcePushImageToMemory") ? image.ForcePushImageToMemory : false + decode := ObjHasOwnProp(image, "decode") ? image.decode : this.decode + validate := ObjHasOwnProp(image, "validate") ? image.validate : this.validate ; Dereference the image unknown. if ObjHasOwnProp(image, "image") @@ -144,8 +141,8 @@ class ImagePut { } else { index := crop := scale := false - ForceDecodeImagePixels := this.ForceDecodeImagePixels - ForcePushImageToMemory := this.ForcePushImageToMemory + decode := this.decode + validate := this.validate } ; Start! @@ -157,7 +154,7 @@ class ImagePut { type := this.ImageType(image) ; #1 - Stream intermediate. - if not ForceDecodeImagePixels and not crop and not scale + if not decode and not crop and not scale and (type ~= "^(?i:url|file|stream|RandomAccessStream|hex|base64)$") and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64)$") and (!p.Has(1) || p[1] == "") { ; For now, disallow any specification of extensions. @@ -184,7 +181,7 @@ class ImagePut { ; Convert via GDI+ bitmap intermediate. pBitmap := this.ToBitmap(type, image, index) - (ForcePushImageToMemory) ? DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmap) : {} + (validate) ? DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmap) : {} (crop) ? this.BitmapCrop(&pBitmap, crop) : {} (scale) ? this.BitmapScale(&pBitmap, scale) : {} coimage := this.BitmapToCoimage(cotype, pBitmap, p*) From c552a060421b992d4c729c02ac4b9e15f194092d Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 11 Dec 2021 13:13:03 -0500 Subject: [PATCH 114/492] Reorganize input as pdf --- ImagePut (for v1).ahk | 88 +++++++++++++++++++++---------------------- ImagePut.ahk | 12 ++++++ 2 files changed, 56 insertions(+), 44 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index aba7dbfd..1afcfcc6 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -245,6 +245,11 @@ class ImagePut { return "cursor" } + if ObjHasKey(image, "pdf") { + image := image.pdf + return "pdf" + } + if ObjHasKey(image, "url") { image := image.url return "url" @@ -255,11 +260,6 @@ class ImagePut { return "file" } - if ObjHasKey(image, "pdf") { - image := image.pdf - return "pdf" - } - if ObjHasKey(image, "monitor") { image := image.monitor return "monitor" @@ -352,17 +352,17 @@ class ImagePut { . "Icon|No|Size|SizeAll|SizeNESW|SizeNS|SizeNWSE|SizeWE|UpArrow|Wait|Unknown)$") return "cursor" + ; A "pdf" is either a file or url with a .pdf extension. + if (image ~= "\.pdf$") && (FileExist(image) || this.is_url(image)) + return "pdf" + ; A "url" satisfies the url format. if this.is_url(image) return "url" ; A "file" is stored on the disk or network. - if FileExist(image) { - if image ~= ".pdf$" - return "pdf" - + if FileExist(image) return "file" - } if (image ~= "^-?\d+$") { SysGet MonitorGetCount, MonitorCount ; A non-zero "monitor" number identifies each display uniquely; and 0 refers to the entire virtual screen. @@ -441,12 +441,12 @@ class ImagePut { if (type = "cursor") return this.from_cursor() - if (type = "url") - return this.from_url(image) - if (type = "pdf") return this.from_pdf(image, index) + if (type = "url") + return this.from_url(image) + if (type = "file") return this.from_file(image) @@ -1018,37 +1018,6 @@ class ImagePut { return pBitmap } - from_url(image) { - pStream := this.get_url(image) - DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", pBitmap:=0) - ObjRelease(pStream) - return pBitmap - } - - get_url(image) { - req := ComObjCreate("WinHttp.WinHttpRequest.5.1") - req.Open("GET", image) - req.Send() - pStream := ComObjQuery(req.ResponseStream, "{0000000C-0000-0000-C000-000000000046}") - return pStream - } - - from_file(image) { - DllCall("gdiplus\GdipCreateBitmapFromFile", "wstr", image, "ptr*", pBitmap:=0) - return pBitmap - } - - get_file(image) { - file := FileOpen(image, "r") - hData := DllCall("GlobalAlloc", "uint", 0x2, "uptr", file.length, "ptr") - pData := DllCall("GlobalLock", "ptr", hData, "ptr") - file.RawRead(pData+0, file.length) - DllCall("GlobalUnlock", "ptr", hData) - file.Close() - DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", true, "ptr*", pStream:=0, "uint") - return pStream - } - from_pdf(image, page) { page := (page) ? page - 1 : 0 ; Zero indexed. @@ -1105,6 +1074,37 @@ class ImagePut { Object := ObjectResult } + from_url(image) { + pStream := this.get_url(image) + DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", pBitmap:=0) + ObjRelease(pStream) + return pBitmap + } + + get_url(image) { + req := ComObjCreate("WinHttp.WinHttpRequest.5.1") + req.Open("GET", image) + req.Send() + pStream := ComObjQuery(req.ResponseStream, "{0000000C-0000-0000-C000-000000000046}") + return pStream + } + + from_file(image) { + DllCall("gdiplus\GdipCreateBitmapFromFile", "wstr", image, "ptr*", pBitmap:=0) + return pBitmap + } + + get_file(image) { + file := FileOpen(image, "r") + hData := DllCall("GlobalAlloc", "uint", 0x2, "uptr", file.length, "ptr") + pData := DllCall("GlobalLock", "ptr", hData, "ptr") + file.RawRead(pData+0, file.length) + DllCall("GlobalUnlock", "ptr", hData) + file.Close() + DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", true, "ptr*", pStream:=0, "uint") + return pStream + } + from_monitor(image) { if (image > 0) { SysGet _, Monitor, image diff --git a/ImagePut.ahk b/ImagePut.ahk index e73a0d7c..a66e2474 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -245,6 +245,11 @@ class ImagePut { return "cursor" } + if ObjHasOwnProp(image, "pdf") { + image := image.pdf + return "pdf" + } + if ObjHasOwnProp(image, "url") { image := image.url return "url" @@ -347,6 +352,10 @@ class ImagePut { . "Icon|No|Size|SizeAll|SizeNESW|SizeNS|SizeNWSE|SizeWE|UpArrow|Wait|Unknown)$") return "cursor" + ; A "pdf" is either a file or url with a .pdf extension. + if (image ~= "\.pdf$") && (FileExist(image) || this.is_url(image)) + return "pdf" + ; A "url" satisfies the url format. if this.is_url(image) return "url" @@ -432,6 +441,9 @@ class ImagePut { if (type = "cursor") return this.from_cursor() + if (type = "pdf") + return this.from_pdf(image, index) + if (type = "url") return this.from_url(image) From 1b014216c30b710ec48cefeaaaeb8e9fa70fc2eb Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 11 Dec 2021 13:19:52 -0500 Subject: [PATCH 115/492] Add credit to malcev for from_pdf --- ImagePut (for v1).ahk | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 1afcfcc6..3865f5d1 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1019,7 +1019,10 @@ class ImagePut { } from_pdf(image, page) { - page := (page) ? page - 1 : 0 ; Zero indexed. + ; Thanks malcev - https://www.autohotkey.com/boards/viewtopic.php?t=80735 + + ; Zero indexed. + page := (page) ? page - 1 : 0 ; Create the "Windows.Data.Pdf.PdfDocument" class using IPdfDocumentStatics. DllCall("combase\WindowsCreateString", "wstr", "Windows.Data.Pdf.PdfDocument", "uint", 28, "ptr*", hString:=0, "uint") From 883e9a8e28e60ac3c630ee66413d69f1e137ae3d Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 11 Dec 2021 20:46:43 -0500 Subject: [PATCH 116/492] Fully support PDFs --- ImagePut (for v1).ahk | 87 ++++++++++++++++++++++++----------- ImagePut.ahk | 104 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 158 insertions(+), 33 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 3865f5d1..180765bb 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -129,20 +129,23 @@ class ImagePut { ; Extract parameters. if IsObject(image) { - index := ObjHasKey(image, "index") ? image.index : false crop := ObjHasKey(image, "crop") ? image.crop : false scale := ObjHasKey(image, "scale") ? image.scale : false decode := ObjHasKey(image, "decode") ? image.decode : this.decode validate := ObjHasKey(image, "validate") ? image.validate : this.validate + index := ObjHasKey(image, "index") ? image.index : 0 + ; Dereference the image unknown. if ObjHasKey(image, "image") image := image.image } else { - index := crop := scale := false + crop := scale := false decode := this.decode validate := this.validate + + index := 0 } ; Start! @@ -155,12 +158,12 @@ class ImagePut { ; #1 - Stream intermediate. if not decode and not crop and not scale - and (type ~= "^(?i:url|file|stream|RandomAccessStream|hex|base64)$") + and (type ~= "^(?i:pdf|url|file|stream|RandomAccessStream|hex|base64)$") and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64)$") and (p[1] = "") { ; For now, disallow any specification of extensions. ; Convert via stream intermediate. - pStream := this.ToStream(type, image) + pStream := this.ToStream(type, image, index) coimage := this.StreamToCoimage(cotype, pStream, p*) ; Prevents the stream object from being freed. @@ -415,7 +418,7 @@ class ImagePut { throw Exception("Image type could not be identified.") } - ToBitmap(type, image, index := "") { + ToBitmap(type, image, index := 0) { if (type = "clipboard") return this.from_clipboard() @@ -555,7 +558,10 @@ class ImagePut { throw Exception("Conversion from bitmap to " cotype " is not supported.") } - ToStream(type, image) { + ToStream(type, image, index := 0) { + + if (type = "pdf") + return this.get_pdf(image, index) if (type = "url") return this.get_url(image) @@ -1018,11 +1024,27 @@ class ImagePut { return pBitmap } - from_pdf(image, page) { + from_pdf(image, index := 0) { + pStream := this.get_pdf(image, index) + DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", pBitmap:=0) + ObjRelease(pStream) + return pBitmap + } + + get_pdf(image, index := 0) { ; Thanks malcev - https://www.autohotkey.com/boards/viewtopic.php?t=80735 ; Zero indexed. - page := (page) ? page - 1 : 0 + index := (index) ? index - 1 : 0 + + ; Create a source pBitmap and extract the width and height. + if !(pStream := this.get_file(image)) + if !(pStream := this.get_url(image)) + throw Exception("Could not be loaded from a valid file path or URL.") + + ; Create a RandomAccessStream with BSOS_PREFERDESTINATIONSTREAM. + DllCall("ole32\CLSIDFromString", "wstr", "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}", "ptr", &CLSID := VarSetCapacity(CLSID, 16), "uint") + DllCall("ShCore\CreateRandomAccessStreamOverStream", "ptr", pStream, "uint", 1, "ptr", &CLSID, "ptr*", pRandomAccessStream:=0, "uint") ; Create the "Windows.Data.Pdf.PdfDocument" class using IPdfDocumentStatics. DllCall("combase\WindowsCreateString", "wstr", "Windows.Data.Pdf.PdfDocument", "uint", 28, "ptr*", hString:=0, "uint") @@ -1030,33 +1052,31 @@ class ImagePut { DllCall("combase\RoGetActivationFactory", "ptr", hString, "ptr", &CLSID, "ptr*", PdfDocumentStatics:=0, "uint") DllCall("combase\WindowsDeleteString", "ptr", hString, "uint") - ; Open a file as a RandomAccessStream. - DllCall("ole32\CLSIDFromString", "wstr", "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}", "ptr", &CLSID := VarSetCapacity(CLSID, 16), "uint") - DllCall("ShCore\CreateRandomAccessStreamOnFile", "wstr", image, "uint", Read := 0, "ptr", &CLSID, "ptr*", IRandomAccessStream, "uint") - ; Create the PDF document. - DllCall(PdfDocument_LoadFromStreamAsync := NumGet(NumGet(PdfDocumentStatics+0)+8*A_PtrSize), "ptr", PdfDocumentStatics, "ptr", IRandomAccessStream, "ptr*", PdfDocument) + DllCall(IPdfDocumentStatics_LoadFromStreamAsync := NumGet(NumGet(PdfDocumentStatics+0)+8*A_PtrSize), "ptr", PdfDocumentStatics, "ptr", pRandomAccessStream, "ptr*", PdfDocument:=0) this.WaitForAsync(PdfDocument) ; Get Page - DllCall(NumGet(NumGet(PdfDocument+0)+6*A_PtrSize), "ptr", PdfDocument, "uint", page, "ptr*", PdfPage) ; GetPage + DllCall(IPdfDocument_GetPage := NumGet(NumGet(PdfDocument+0)+6*A_PtrSize), "ptr", PdfDocument, "uint", index, "ptr*", PdfPage:=0) ; Render the page to an output stream. - DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "uint", true, "ptr*", IStream) + DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "uint", true, "ptr*", pStreamOut:=0) DllCall("ole32\CLSIDFromString", "wstr", "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}", "ptr", &CLSID := VarSetCapacity(CLSID, 16), "uint") - DllCall("ShCore\CreateRandomAccessStreamOverStream", "ptr", IStream, "uint", BSOS_DEFAULT := 0, "ptr", &CLSID, "ptr*", IRandomAccessStreamOut) - DllCall(NumGet(NumGet(PdfPage+0)+6*A_PtrSize), "ptr", PdfPage, "ptr", IRandomAccessStreamOut, "ptr*", asyncInfo) ; RenderToStreamAsync - this.WaitForAsync(asyncInfo) + DllCall("ShCore\CreateRandomAccessStreamOverStream", "ptr", pStreamOut, "uint", BSOS_DEFAULT := 0, "ptr", &CLSID, "ptr*", pRandomAccessStreamOut:=0) + DllCall(IPdfPage_RenderToStreamAsync := NumGet(NumGet(PdfPage+0)+6*A_PtrSize), "ptr", PdfPage, "ptr", pRandomAccessStreamOut, "ptr*", AsyncInfo:=0) + this.WaitForAsync(AsyncInfo) - DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", IStream, "ptr*", pBitmap:=0) + ; Cleanup + this.ObjReleaseClose(pRandomAccessStreamOut) + this.ObjReleaseClose(PdfPage) - ObjRelease(IRandomAccessStreamOut) - ObjRelease(IStream) - ObjRelease(PdfPage) ObjRelease(PdfDocument) - ObjRelease(IRandomAccessStream) ObjRelease(PdfDocumentStatics) - return pBitmap + + this.ObjReleaseClose(pRandomAccessStream) + ObjRelease(pStream) + + return pStreamOut } WaitForAsync(ByRef Object) { @@ -1070,11 +1090,24 @@ class ImagePut { throw Exception("AsyncInfo status error: " ErrorCode) } - ObjRelease(AsyncInfo) - - DllCall(NumGet(NumGet(Object+0)+8*A_PtrSize), "ptr", Object, "ptr*", ObjectResult) ; GetResults + DllCall(NumGet(NumGet(Object+0)+8*A_PtrSize), "ptr", Object, "ptr*", ObjectResult:=0) ; GetResults ObjRelease(Object) Object := ObjectResult + + DllCall(IAsyncInfo_Close := NumGet(NumGet(AsyncInfo+0)+10*A_PtrSize), "ptr", AsyncInfo) + ObjRelease(AsyncInfo) + } + + ObjReleaseClose(ByRef Object) { + if Object { + if (Close := ComObjQuery(Object, IClosable := "{30D5A829-7FA4-4026-83BB-D75BAE4EA99E}")) { + DllCall(IClosable_Close := NumGet(NumGet(Close+0)+6*A_PtrSize), "ptr", Close) + ObjRelease(Close) + } + refcount := ObjRelease(Object) + Object := "" + return refcount + } } from_url(image) { diff --git a/ImagePut.ahk b/ImagePut.ahk index a66e2474..2e19a763 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -129,20 +129,23 @@ class ImagePut { ; Extract parameters. if IsObject(image) { - index := ObjHasOwnProp(image, "index") ? image.index : false crop := ObjHasOwnProp(image, "crop") ? image.crop : false scale := ObjHasOwnProp(image, "scale") ? image.scale : false decode := ObjHasOwnProp(image, "decode") ? image.decode : this.decode validate := ObjHasOwnProp(image, "validate") ? image.validate : this.validate + index := ObjHasOwnProp(image, "index") ? image.index : 0 + ; Dereference the image unknown. if ObjHasOwnProp(image, "image") image := image.image } else { - index := crop := scale := false + crop := scale := false decode := this.decode validate := this.validate + + index := 0 } ; Start! @@ -155,12 +158,12 @@ class ImagePut { ; #1 - Stream intermediate. if not decode and not crop and not scale - and (type ~= "^(?i:url|file|stream|RandomAccessStream|hex|base64)$") + and (type ~= "^(?i:pdf|url|file|stream|RandomAccessStream|hex|base64)$") and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64)$") and (!p.Has(1) || p[1] == "") { ; For now, disallow any specification of extensions. ; Convert via stream intermediate. - pStream := this.ToStream(type, image) + pStream := this.ToStream(type, image, index) coimage := this.StreamToCoimage(cotype, pStream, p*) ; Prevents the stream object from being freed. @@ -415,7 +418,7 @@ class ImagePut { throw Error("Image type could not be identified.") } - static ToBitmap(type, image, index := "") { + static ToBitmap(type, image, index := 0) { if (type = "clipboard") return this.from_clipboard() @@ -555,7 +558,10 @@ class ImagePut { throw Error("Conversion from bitmap to " cotype " is not supported.") } - static ToStream(type, image) { + static ToStream(type, image, index := 0) { + + if (type = "pdf") + return this.get_pdf(image, index) if (type = "url") return this.get_url(image) @@ -1018,6 +1024,92 @@ class ImagePut { return pBitmap } + static from_pdf(image, index := 0) { + pStream := this.get_pdf(image, index) + DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", &pBitmap:=0) + ObjRelease(pStream) + return pBitmap + } + + static get_pdf(image, index := 0) { + ; Thanks malcev - https://www.autohotkey.com/boards/viewtopic.php?t=80735 + + ; Zero indexed. + index := (index) ? index - 1 : 0 + + ; Create a source pBitmap and extract the width and height. + if !(pStream := this.get_file(image)) + if !(pStream := this.get_url(image)) + throw Error("Could not be loaded from a valid file path or URL.") + + ; Create a RandomAccessStream with BSOS_PREFERDESTINATIONSTREAM. + DllCall("ole32\CLSIDFromString", "wstr", "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}", "ptr", CLSID := Buffer(16), "HRESULT") + DllCall("ShCore\CreateRandomAccessStreamOverStream", "ptr", pStream, "uint", 1, "ptr", CLSID, "ptr*", &pRandomAccessStream:=0, "HRESULT") + + ; Create the "Windows.Data.Pdf.PdfDocument" class using IPdfDocumentStatics. + DllCall("combase\WindowsCreateString", "wstr", "Windows.Data.Pdf.PdfDocument", "uint", 28, "ptr*", &hString:=0, "HRESULT") + DllCall("ole32\CLSIDFromString", "wstr", "{433A0B5F-C007-4788-90F2-08143D922599}", "ptr", CLSID := Buffer(16), "HRESULT") + DllCall("combase\RoGetActivationFactory", "ptr", hString, "ptr", CLSID, "ptr*", &PdfDocumentStatics:=0, "HRESULT") + DllCall("combase\WindowsDeleteString", "ptr", hString, "HRESULT") + + ; Create the PDF document. + ComCall(IPdfDocumentStatics_LoadFromStreamAsync := 8, PdfDocumentStatics, "ptr", pRandomAccessStream, "ptr*", &PdfDocument:=0) + this.WaitForAsync(&PdfDocument) + + ; Get Page + ComCall(IPdfDocument_GetPage := 6, PdfDocument, "uint", index, "ptr*", &PdfPage:=0) + + ; Render the page to an output stream. + DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "uint", true, "ptr*", &pStreamOut:=0) + DllCall("ole32\CLSIDFromString", "wstr", "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}", "ptr", CLSID := Buffer(16), "HRESULT") + DllCall("ShCore\CreateRandomAccessStreamOverStream", "ptr", pStreamOut, "uint", BSOS_DEFAULT := 0, "ptr", CLSID, "ptr*", &pRandomAccessStreamOut:=0) + ComCall(IPdfPage_RenderToStreamAsync := 6, PdfPage, "ptr", pRandomAccessStreamOut, "ptr*", &AsyncInfo:=0) + this.WaitForAsync(&AsyncInfo) + + ; Cleanup + this.ObjReleaseClose(&pRandomAccessStreamOut) + this.ObjReleaseClose(&PdfPage) + + ObjRelease(PdfDocument) + ObjRelease(PdfDocumentStatics) + + this.ObjReleaseClose(&pRandomAccessStream) + ObjRelease(pStream) + + return pStreamOut + } + + static WaitForAsync(&Object) { + AsyncInfo := ComObjQuery(Object, IAsyncInfo := "{00000036-0000-0000-C000-000000000046}") + while !ComCall(IAsyncInfo_Status := 7, AsyncInfo, "uint*", &status:=0) + and (status = 0) + Sleep 10 + + if (status != 1) { + ComCall(IAsyncInfo_ErrorCode := 8, AsyncInfo, "uint*", &ErrorCode:=0) + throw Error("AsyncInfo status error: " ErrorCode) + } + + ComCall(8, Object, "ptr*", &ObjectResult:=0) ; GetResults + ObjRelease(Object) + Object := ObjectResult + + ComCall(IAsyncInfo_Close := 10, AsyncInfo) + AsyncInfo := "" + } + + static ObjReleaseClose(&Object) { + if Object { + if (Close := ComObjQuery(Object, IClosable := "{30D5A829-7FA4-4026-83BB-D75BAE4EA99E}")) { + ComCall(IClosable_Close := 6, Close) + Close := "" + } + refcount := ObjRelease(Object) + Object := "" + return refcount + } + } + static from_url(image) { pStream := this.get_url(image) DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", &pBitmap:=0) From 4012c20eb6a73443b865a8040715aac2c1d43640 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 11 Dec 2021 21:04:41 -0500 Subject: [PATCH 117/492] Add better error message when PDF pages exceed count --- ImagePut (for v1).ahk | 3 +++ ImagePut.ahk | 3 +++ 2 files changed, 6 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 180765bb..8419a8da 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1057,6 +1057,9 @@ class ImagePut { this.WaitForAsync(PdfDocument) ; Get Page + DllCall(IPdfDocument_GetPage := NumGet(NumGet(PdfDocument+0)+7*A_PtrSize), "ptr", PdfDocument, "uint*", count:=0) + if (index > count) + throw Exception("The maximum number of pages in this pdf is " count ".") DllCall(IPdfDocument_GetPage := NumGet(NumGet(PdfDocument+0)+6*A_PtrSize), "ptr", PdfDocument, "uint", index, "ptr*", PdfPage:=0) ; Render the page to an output stream. diff --git a/ImagePut.ahk b/ImagePut.ahk index 2e19a763..f1c3273a 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1057,6 +1057,9 @@ class ImagePut { this.WaitForAsync(&PdfDocument) ; Get Page + ComCall(IPdfDocument_GetPage := 7, PdfDocument, "uint*", &count:=0) + if (index > count) + throw Error("The maximum number of pages in this pdf is " count ".") ComCall(IPdfDocument_GetPage := 6, PdfDocument, "uint", index, "ptr*", &PdfPage:=0) ; Render the page to an output stream. From 1f2547728990d1645ce0772e40f3d56c36e23753 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 11 Dec 2021 21:58:23 -0500 Subject: [PATCH 118/492] Allow urls inside pdfs --- ImagePut (for v1).ahk | 16 +++++++++------- ImagePut.ahk | 16 +++++++++------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 8419a8da..aa345d07 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1034,13 +1034,14 @@ class ImagePut { get_pdf(image, index := 0) { ; Thanks malcev - https://www.autohotkey.com/boards/viewtopic.php?t=80735 - ; Zero indexed. - index := (index) ? index - 1 : 0 + ; Create a stream from either a url or a file. + if this.is_url(image) + pStream := this.get_url(image) + else + pStream := this.get_file(image) - ; Create a source pBitmap and extract the width and height. - if !(pStream := this.get_file(image)) - if !(pStream := this.get_url(image)) - throw Exception("Could not be loaded from a valid file path or URL.") + if !(pStream) + throw Exception("Could not be loaded from a valid file path or URL.") ; Create a RandomAccessStream with BSOS_PREFERDESTINATIONSTREAM. DllCall("ole32\CLSIDFromString", "wstr", "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}", "ptr", &CLSID := VarSetCapacity(CLSID, 16), "uint") @@ -1058,7 +1059,8 @@ class ImagePut { ; Get Page DllCall(IPdfDocument_GetPage := NumGet(NumGet(PdfDocument+0)+7*A_PtrSize), "ptr", PdfDocument, "uint*", count:=0) - if (index > count) + index := (index > 0) ? index - 1 : (index < 0) ? count + index : 0 ; Zero indexed. + if (index > count || index < 0) throw Exception("The maximum number of pages in this pdf is " count ".") DllCall(IPdfDocument_GetPage := NumGet(NumGet(PdfDocument+0)+6*A_PtrSize), "ptr", PdfDocument, "uint", index, "ptr*", PdfPage:=0) diff --git a/ImagePut.ahk b/ImagePut.ahk index f1c3273a..936c7292 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1034,13 +1034,14 @@ class ImagePut { static get_pdf(image, index := 0) { ; Thanks malcev - https://www.autohotkey.com/boards/viewtopic.php?t=80735 - ; Zero indexed. - index := (index) ? index - 1 : 0 + ; Create a stream from either a url or a file.- + if this.is_url(image) + pStream := this.get_url(image) + else + pStream := this.get_file(image) - ; Create a source pBitmap and extract the width and height. - if !(pStream := this.get_file(image)) - if !(pStream := this.get_url(image)) - throw Error("Could not be loaded from a valid file path or URL.") + if !(pStream) + throw Error("Could not be loaded from a valid file path or URL.") ; Create a RandomAccessStream with BSOS_PREFERDESTINATIONSTREAM. DllCall("ole32\CLSIDFromString", "wstr", "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}", "ptr", CLSID := Buffer(16), "HRESULT") @@ -1058,7 +1059,8 @@ class ImagePut { ; Get Page ComCall(IPdfDocument_GetPage := 7, PdfDocument, "uint*", &count:=0) - if (index > count) + index := (index > 0) ? index - 1 : (index < 0) ? count + index : 0 ; Zero indexed. + if (index > count || index < 0) throw Error("The maximum number of pages in this pdf is " count ".") ComCall(IPdfDocument_GetPage := 6, PdfDocument, "uint", index, "ptr*", &PdfPage:=0) From 9d6d293c3056446581e4bf65304717b5b825b893 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 12 Dec 2021 00:21:43 -0500 Subject: [PATCH 119/492] Use magic numbers to verify PDF --- ImagePut (for v1).ahk | 10 +++++----- ImagePut.ahk | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index aa345d07..89674e67 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1035,12 +1035,12 @@ class ImagePut { ; Thanks malcev - https://www.autohotkey.com/boards/viewtopic.php?t=80735 ; Create a stream from either a url or a file. - if this.is_url(image) - pStream := this.get_url(image) - else - pStream := this.get_file(image) + pStream := this.is_url(image) ? this.get_url(image) : this.get_file(image) - if !(pStream) + ; Compare the signature of the file with the PDF magic string "%PDF". + DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", &signature := VarSetCapacity(signature, 4), "uint", 4, "uint") + StrPut("%PDF", &magic := VarSetCapacity(magic, 4), "CP0") + if 4 > DllCall("ntdll\RtlCompareMemory", "ptr", &signature, "ptr", &magic, "uptr", 4, "uptr") throw Exception("Could not be loaded from a valid file path or URL.") ; Create a RandomAccessStream with BSOS_PREFERDESTINATIONSTREAM. diff --git a/ImagePut.ahk b/ImagePut.ahk index 936c7292..8b8bfc80 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1034,13 +1034,13 @@ class ImagePut { static get_pdf(image, index := 0) { ; Thanks malcev - https://www.autohotkey.com/boards/viewtopic.php?t=80735 - ; Create a stream from either a url or a file.- - if this.is_url(image) - pStream := this.get_url(image) - else - pStream := this.get_file(image) + ; Create a stream from either a url or a file. + pStream := this.is_url(image) ? this.get_url(image) : this.get_file(image) - if !(pStream) + ; Compare the signature of the file with the PDF magic string "%PDF". + DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", signature := Buffer(4), "uint", 4, "HRESULT") + StrPut("%PDF", magic := Buffer(4), "CP0") + if 4 > DllCall("ntdll\RtlCompareMemory", "ptr", signature, "ptr", magic, "uptr", 4, "uptr") throw Error("Could not be loaded from a valid file path or URL.") ; Create a RandomAccessStream with BSOS_PREFERDESTINATIONSTREAM. From 47bc6a71d58ed7369ae7ed2ad08c4f3d8978dc22 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 12 Dec 2021 00:42:10 -0500 Subject: [PATCH 120/492] Use asynchronous WinHttp request --- ImagePut (for v1).ahk | 3 ++- ImagePut.ahk | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 89674e67..32c89cdb 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1124,8 +1124,9 @@ class ImagePut { get_url(image) { req := ComObjCreate("WinHttp.WinHttpRequest.5.1") - req.Open("GET", image) + req.Open("GET", image, true) req.Send() + req.WaitForResponse() pStream := ComObjQuery(req.ResponseStream, "{0000000C-0000-0000-C000-000000000046}") return pStream } diff --git a/ImagePut.ahk b/ImagePut.ahk index 8b8bfc80..56d27d7a 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1124,8 +1124,9 @@ class ImagePut { static get_url(image) { req := ComObject("WinHttp.WinHttpRequest.5.1") - req.Open("GET", image) + req.Open("GET", image, true) req.Send() + req.WaitForResponse() IStream := ComObjQuery(req.ResponseStream, "{0000000C-0000-0000-C000-000000000046}"), ObjAddRef(IStream.ptr) return IStream.ptr } From 7c1901bb977f1eb5741b98261643409429ad9a6e Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 12 Dec 2021 12:24:52 -0500 Subject: [PATCH 121/492] Fix memory leak --- ImagePut (for v1).ahk | 7 ++++++- ImagePut.ahk | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 32c89cdb..3f8c8ee2 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1060,8 +1060,13 @@ class ImagePut { ; Get Page DllCall(IPdfDocument_GetPage := NumGet(NumGet(PdfDocument+0)+7*A_PtrSize), "ptr", PdfDocument, "uint*", count:=0) index := (index > 0) ? index - 1 : (index < 0) ? count + index : 0 ; Zero indexed. - if (index > count || index < 0) + if (index > count || index < 0) { + ObjRelease(PdfDocument) + ObjRelease(PdfDocumentStatics) + this.ObjReleaseClose(pRandomAccessStream) + ObjRelease(pStream) throw Exception("The maximum number of pages in this pdf is " count ".") + } DllCall(IPdfDocument_GetPage := NumGet(NumGet(PdfDocument+0)+6*A_PtrSize), "ptr", PdfDocument, "uint", index, "ptr*", PdfPage:=0) ; Render the page to an output stream. diff --git a/ImagePut.ahk b/ImagePut.ahk index 56d27d7a..7babe7b7 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1060,8 +1060,13 @@ class ImagePut { ; Get Page ComCall(IPdfDocument_GetPage := 7, PdfDocument, "uint*", &count:=0) index := (index > 0) ? index - 1 : (index < 0) ? count + index : 0 ; Zero indexed. - if (index > count || index < 0) + if (index > count || index < 0) { + ObjRelease(PdfDocument) + ObjRelease(PdfDocumentStatics) + this.ObjReleaseClose(&pRandomAccessStream) + ObjRelease(pStream) throw Error("The maximum number of pages in this pdf is " count ".") + } ComCall(IPdfDocument_GetPage := 6, PdfDocument, "uint", index, "ptr*", &PdfPage:=0) ; Render the page to an output stream. From c19ed6acb6aac8f89d16155b4f70ec377e510f78 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 1 Jan 2022 16:08:15 -0500 Subject: [PATCH 122/492] Document Critical Error ObjRelease behavior Scenarios where error is not critical: 0-4095 (v1) 0-65535 (v2) --- ImagePut (for v1).ahk | 1 + ImagePut.ahk | 1 + 2 files changed, 2 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 3f8c8ee2..31c87297 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -390,6 +390,7 @@ class ImagePut { ; Note 1: All GDI+ functions add 1 to the reference count of COM objects. ; Note 2: GDI+ pBitmaps that are queried cease to stay pBitmaps. + ; Note 3: Critical error for ranges 0-4095 on v1 and 0-65535 on v2. ObjRelease(image) ; Therefore do not move this, it has been tested. ; A "stream" is a pointer to the IStream interface. diff --git a/ImagePut.ahk b/ImagePut.ahk index 7babe7b7..10cdb4e2 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -390,6 +390,7 @@ class ImagePut { ; Note 1: All GDI+ functions add 1 to the reference count of COM objects. ; Note 2: GDI+ pBitmaps that are queried cease to stay pBitmaps. + ; Note 3: Critical error for ranges 0-4095 on v1 and 0-65535 on v2. ObjRelease(image) ; Therefore do not move this, it has been tested. ; A "stream" is a pointer to the IStream interface. From 16bb578141e88a0f868ba5cdd60784abd76e5637 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 1 Jan 2022 20:12:36 -0500 Subject: [PATCH 123/492] Split clipboard PNG streams and GDI bitmaps --- ImagePut (for v1).ahk | 94 ++++++++++++++++++++++++++++++------------- ImagePut.ahk | 84 +++++++++++++++++++++++++++----------- 2 files changed, 127 insertions(+), 51 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 31c87297..c6b91074 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -158,9 +158,9 @@ class ImagePut { ; #1 - Stream intermediate. if not decode and not crop and not scale - and (type ~= "^(?i:pdf|url|file|stream|RandomAccessStream|hex|base64)$") + and (type ~= "^(?i:clipboard_png|pdf|url|file|stream|RandomAccessStream|hex|base64)$") and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64)$") - and (p[1] = "") { ; For now, disallow any specification of extensions. + and (p[1] == "") { ; For now, disallow any specification of extensions. ; Convert via stream intermediate. pStream := this.ToStream(type, image, index) @@ -208,6 +208,11 @@ class ImagePut { ; Check for image type declarations. ; Assumes that the user is telling the truth. + if ObjHasKey(image, "clipboard_png") { + image := image.clipboard_png + return "clipboard_png" + } + if ObjHasKey(image, "clipboard") { image := image.clipboard return "clipboard" @@ -317,14 +322,22 @@ class ImagePut { } ImageType(image) { + ; Throw if the image is an empty string. if (image == "") { - DllCall("OpenClipboard", "ptr", A_ScriptHwnd) - result := !DllCall("IsClipboardFormatAvailable", "uint", DllCall("RegisterClipboardFormat", "str", "png", "uint")) && !DllCall("IsClipboardFormatAvailable", "uint", 2) - DllCall("CloseClipboard") - if !(result) - return "clipboard" - throw Exception("Image data is an empty string.") - } + + + + + ; A "clipboard_png" is a pointer to a PNG stream saved as the "png" clipboard format. + if DllCall("IsClipboardFormatAvailable", "uint", DllCall("RegisterClipboardFormat", "str", "png", "uint")) + return "clipboard_png" + + ; A "clipboard" is a handle to a GDI bitmap saved as CF_BITMAP. + if DllCall("IsClipboardFormatAvailable", "uint", 2) + return "clipboard" + + throw Exception("Image data is an empty string.") + } if IsObject(image) { ; A "object" has a pBitmap property that points to an internal GDI+ bitmap. if image.HasKey("pBitmap") @@ -421,6 +434,9 @@ class ImagePut { ToBitmap(type, image, index := 0) { + if (type = "clipboard_png") + return this.from_clipboard_png() + if (type = "clipboard") return this.from_clipboard() @@ -561,6 +577,9 @@ class ImagePut { ToStream(type, image, index := 0) { + if (type = "clipboard_png") + return this.get_clipboard_png() + if (type = "pdf") return this.get_pdf(image, index) @@ -812,31 +831,50 @@ class ImagePut { Sleep (2**(A_Index-1) * 30) else throw Exception("Clipboard could not be opened.") - ; Prefer the PNG stream if available because of transparency support. - png := DllCall("RegisterClipboardFormat", "str", "png", "uint") - if DllCall("IsClipboardFormatAvailable", "uint", png) { - if !(hData := DllCall("GetClipboardData", "uint", png, "ptr")) - throw Exception("Shared clipboard data has been deleted.") - - ; Allow the stream to be freed while leaving the hData intact. - ; Please read: https://devblogs.microsoft.com/oldnewthing/20210930-00/?p=105745 - DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", false, "ptr*", pStream:=0, "uint") - DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", pBitmap:=0) - ObjRelease(pStream) - } - ; Fallback to CF_BITMAP. This format does not support transparency even with put_hBitmap(). - else if DllCall("IsClipboardFormatAvailable", "uint", 2) { - if !(hbm := DllCall("GetClipboardData", "uint", 2, "ptr")) - throw Exception("Shared clipboard data has been deleted.") - DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "ptr", hbm, "ptr", 0, "ptr*", pBitmap:=0) - DllCall("DeleteObject", "ptr", hbm) - } + if !DllCall("IsClipboardFormatAvailable", "uint", 2) + throw Exception("Clipboard does not have CF_BITMAP data.") + + if !(hbm := DllCall("GetClipboardData", "uint", 2, "ptr")) + throw Exception("Shared clipboard data has been deleted.") + DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "ptr", hbm, "ptr", 0, "ptr*", pBitmap:=0) + DllCall("DeleteObject", "ptr", hbm) DllCall("CloseClipboard") return pBitmap } + from_clipboard_png() { + pStream := this.get_clipboard_png() + DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", pBitmap:=0) + ObjRelease(pStream) + return pBitmap + } + + get_clipboard_png() { + ; Open the clipboard with exponential backoff. + loop + if DllCall("OpenClipboard", "ptr", A_ScriptHwnd) + break + else + if A_Index < 6 + Sleep (2**(A_Index-1) * 30) + else throw Exception("Clipboard could not be opened.") + + png := DllCall("RegisterClipboardFormat", "str", "png", "uint") + if !DllCall("IsClipboardFormatAvailable", "uint", png) + throw Exception("Clipboard does not have PNG stream data.") + + if !(hData := DllCall("GetClipboardData", "uint", png, "ptr")) + throw Exception("Shared clipboard data has been deleted.") + + ; Allow the stream to be freed while leaving the hData intact. + ; Please read: https://devblogs.microsoft.com/oldnewthing/20210930-00/?p=105745 + DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", false, "ptr*", pStream:=0, "uint") + DllCall("CloseClipboard") + return pStream + } + from_object(image) { return this.from_bitmap(image.pBitmap) } diff --git a/ImagePut.ahk b/ImagePut.ahk index 10cdb4e2..32868ad2 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -158,7 +158,7 @@ class ImagePut { ; #1 - Stream intermediate. if not decode and not crop and not scale - and (type ~= "^(?i:pdf|url|file|stream|RandomAccessStream|hex|base64)$") + and (type ~= "^(?i:clipboard_png|pdf|url|file|stream|RandomAccessStream|hex|base64)$") and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64)$") and (!p.Has(1) || p[1] == "") { ; For now, disallow any specification of extensions. @@ -208,6 +208,11 @@ class ImagePut { ; Check for image type declarations. ; Assumes that the user is telling the truth. + if ObjHasOwnProp(image, "clipboard_png") { + image := image.clipboard_png + return "clipboard_png" + } + if ObjHasOwnProp(image, "clipboard") { image := image.clipboard return "clipboard" @@ -322,9 +327,17 @@ class ImagePut { throw Error("Image data is an empty string.") if IsObject(image) { - ; A "clipboard" is a buffer object containing binary data returned by ClipboardAll() - if (image.base.HasOwnProp("__class") && image.base.__class == "ClipboardAll") - return "clipboard" + if (image.base.HasOwnProp("__class") && image.base.__class == "ClipboardAll") { + ; A "clipboard_png" is a pointer to a PNG stream saved as the "png" clipboard format. + if DllCall("IsClipboardFormatAvailable", "uint", DllCall("RegisterClipboardFormat", "str", "png", "uint")) + return "clipboard_png" + + ; A "clipboard" is a handle to a GDI bitmap saved as CF_BITMAP. + if DllCall("IsClipboardFormatAvailable", "uint", 2) + return "clipboard" + + throw Error("Clipboard format not supported.") + } ; A "object" has a pBitmap property that points to an internal GDI+ bitmap. if image.HasOwnProp("pBitmap") @@ -421,6 +434,9 @@ class ImagePut { static ToBitmap(type, image, index := 0) { + if (type = "clipboard_png") + return this.from_clipboard_png() + if (type = "clipboard") return this.from_clipboard() @@ -561,6 +577,9 @@ class ImagePut { static ToStream(type, image, index := 0) { + if (type = "clipboard_png") + return this.get_clipboard_png() + if (type = "pdf") return this.get_pdf(image, index) @@ -812,31 +831,50 @@ class ImagePut { Sleep (2**(A_Index-1) * 30) else throw Error("Clipboard could not be opened.") - ; Prefer the PNG stream if available because of transparency support. - png := DllCall("RegisterClipboardFormat", "str", "png", "uint") - if DllCall("IsClipboardFormatAvailable", "uint", png) { - if !(hData := DllCall("GetClipboardData", "uint", png, "ptr")) - throw Error("Shared clipboard data has been deleted.") - - ; Allow the stream to be freed while leaving the hData intact. - ; Please read: https://devblogs.microsoft.com/oldnewthing/20210930-00/?p=105745 - DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", false, "ptr*", &pStream:=0, "HRESULT") - DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", &pBitmap:=0) - ObjRelease(pStream) - } - ; Fallback to CF_BITMAP. This format does not support transparency even with put_hBitmap(). - else if DllCall("IsClipboardFormatAvailable", "uint", 2) { - if !(hbm := DllCall("GetClipboardData", "uint", 2, "ptr")) - throw Error("Shared clipboard data has been deleted.") - DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "ptr", hbm, "ptr", 0, "ptr*", &pBitmap:=0) - DllCall("DeleteObject", "ptr", hbm) - } + if !DllCall("IsClipboardFormatAvailable", "uint", 2) + throw Error("Clipboard does not have CF_BITMAP data.") + if !(hbm := DllCall("GetClipboardData", "uint", 2, "ptr")) + throw Error("Shared clipboard data has been deleted.") + + DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "ptr", hbm, "ptr", 0, "ptr*", &pBitmap:=0) + DllCall("DeleteObject", "ptr", hbm) DllCall("CloseClipboard") return pBitmap } + static from_clipboard_png() { + pStream := this.get_clipboard_png() + DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", &pBitmap:=0) + ObjRelease(pStream) + return pBitmap + } + + static get_clipboard_png() { + ; Open the clipboard with exponential backoff. + loop + if DllCall("OpenClipboard", "ptr", A_ScriptHwnd) + break + else + if A_Index < 6 + Sleep (2**(A_Index-1) * 30) + else throw Error("Clipboard could not be opened.") + + png := DllCall("RegisterClipboardFormat", "str", "png", "uint") + if !DllCall("IsClipboardFormatAvailable", "uint", png) + throw Error("Clipboard does not have PNG stream data.") + + if !(hData := DllCall("GetClipboardData", "uint", png, "ptr")) + throw Error("Shared clipboard data has been deleted.") + + ; Allow the stream to be freed while leaving the hData intact. + ; Please read: https://devblogs.microsoft.com/oldnewthing/20210930-00/?p=105745 + DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", false, "ptr*", &pStream:=0, "HRESULT") + DllCall("CloseClipboard") + return pStream + } + static from_object(image) { return this.from_bitmap(image.pBitmap) } From 905ebb2c101738e01239266e93030794f5c0d426 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 1 Jan 2022 21:25:49 -0500 Subject: [PATCH 124/492] v1.4 --- ImagePut (for v1).ahk | 4 ++-- ImagePut.ahk | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index c6b91074..26ba799c 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1,8 +1,8 @@ ; Script: ImagePut.ahk ; License: MIT License ; Author: Edison Hua (iseahound) -; Date: 2021-10-07 -; Version: 1.3.0 +; Date: 2022-01-01 +; Version: 1.4.0 #Requires AutoHotkey v1.1.33+ diff --git a/ImagePut.ahk b/ImagePut.ahk index 32868ad2..ad1fffc8 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1,8 +1,8 @@ ; Script: ImagePut.ahk ; License: MIT License ; Author: Edison Hua (iseahound) -; Date: 2021-10-07 -; Version: 1.3.0 +; Date: 2022-01-01 +; Version: 1.4.0 #Requires AutoHotkey v2.0-beta.3+ From 11d830a23e6fb3cba547ae04e7f5c184e21152e8 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 1 Jan 2022 22:01:05 -0500 Subject: [PATCH 125/492] Update README.md --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 9750d034..b363a2b1 100644 --- a/README.md +++ b/README.md @@ -36,15 +36,15 @@ or something like this: Working with images should be this easy. ImagePut has automatic type inference, meaning that it will guess whether the input is (1) a file (2) a website url or (3) a series of coordinates that map to the screen. This functionality enables the user to only memorize a single function for any possible input. For a full list of supported input types, click on the documentation link [here](https://github.com/iseahound/ImagePut/wiki/Input-Types-&-Output-Functions#input-types). For output types click [here](https://github.com/iseahound/ImagePut/wiki/Input-Types-&-Output-Functions#output-functions). -Converting between file formats is also straightforward. +Conversion between file formats is straightforward. ; Saves a JPEG as a GIF. ImagePutFile("cats.jpg", "gif") -You can also move between different image types and file formats. +Convert file formats and image types at the same time! - ; Returns a base64 encoded GIF. - ImagePutBase64("cats.jpg", "gif") + ; Saves a JPEG as a base64 encoded GIF. + str := ImagePutBase64("cats.jpg", "gif") There's also some weird functions like ```ImagePutCursor``` which lets you set anything as your cursor. Make sure you don't choose an extremely large image! @@ -54,12 +54,12 @@ Finally, there are several advanced features. The first is the ability to specif ImagePutWindow({file: "cats.jpg"}) ; Scale 2x and crop 10% from each edge. - ImagePutScreenshot({file: "cats.jpg", scale: 2, crop:["-10%", "-10%", "-10%", "-10%"]}) + ImagePutWindow({file: "cats.jpg", scale: 2, crop:["-10%", "-10%", "-10%", "-10%"]}) ; Unknown image type declared as "image" to be cropped to 200x200 pixels. - ImagePutScreenshot({image: "cats.jpg", crop: [0, 0, 200, 200]}) + ImagePutWindow({image: "cats.jpg", crop: [0, 0, 200, 200]}) - ; Compare a url to a file + ; Compare a url to a file. MsgBox % ImageEqual("https://example.com/cats.jpg", "cats.jpg") ; Validate an image as an actual image. From d63df9b7dccf614f3e5c563fe7c8aee9c7763c8f Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 1 Jan 2022 23:07:50 -0500 Subject: [PATCH 126/492] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b363a2b1..7d5ba027 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ or something like this: Working with images should be this easy. ImagePut has automatic type inference, meaning that it will guess whether the input is (1) a file (2) a website url or (3) a series of coordinates that map to the screen. This functionality enables the user to only memorize a single function for any possible input. For a full list of supported input types, click on the documentation link [here](https://github.com/iseahound/ImagePut/wiki/Input-Types-&-Output-Functions#input-types). For output types click [here](https://github.com/iseahound/ImagePut/wiki/Input-Types-&-Output-Functions#output-functions). -Conversion between file formats is straightforward. +Convert file formats. ; Saves a JPEG as a GIF. ImagePutFile("cats.jpg", "gif") From 2d404f0cd8958df16e5476ee82c1155d812b4cd4 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 2 Jan 2022 00:26:04 -0500 Subject: [PATCH 127/492] Set cursors without local variable. --- ImagePut (for v1).ahk | 7 +++---- ImagePut.ahk | 7 +++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 26ba799c..9a37a8c3 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1876,10 +1876,9 @@ class ImagePut { DllCall("DeleteObject", "ptr", NumGet(ii, 8+2*A_PtrSize, "ptr")) ; hbmColor } - ; Loop over all 16 system cursors and change them all to the new cursor. - SystemCursors := "32512,32513,32514,32515,32516,32642,32643,32644,32645,32646,32648,32649,32650,32651" - Loop Parse, SystemCursors, % "," - { ; Must copy the handle 16 times as SetSystemCursor deletes the handle 16 times. + ; Set all 14 System Cursors. Must CopyImage 14 times as SetSystemCursor deletes the handle each time. + Loop Parse, "32512,32513,32514,32515,32516,32642,32643,32644,32645,32646,32648,32649,32650,32651", % "," + { hCursor := DllCall("CopyImage", "ptr", hIcon, "uint", 2, "int", 0, "int", 0, "uint", 0, "ptr") DllCall("SetSystemCursor", "ptr", hCursor, "int", A_LoopField) ; calls DestroyCursor } diff --git a/ImagePut.ahk b/ImagePut.ahk index ad1fffc8..553d22b6 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1967,10 +1967,9 @@ else { DllCall("DeleteObject", "ptr", NumGet(ii, 8+2*A_PtrSize, "ptr")) ; hbmColor } - ; Loop over all 16 system cursors and change them all to the new cursor. - SystemCursors := "32512,32513,32514,32515,32516,32642,32643,32644,32645,32646,32648,32649,32650,32651" - Loop Parse, SystemCursors, "," - { ; Must copy the handle 16 times as SetSystemCursor deletes the handle 16 times. + ; Set all 14 System Cursors. Must CopyImage 14 times as SetSystemCursor deletes the handle each time. + Loop Parse, "32512,32513,32514,32515,32516,32642,32643,32644,32645,32646,32648,32649,32650,32651", "," + { hCursor := DllCall("CopyImage", "ptr", hIcon, "uint", 2, "int", 0, "int", 0, "uint", 0, "ptr") DllCall("SetSystemCursor", "ptr", hCursor, "int", A_LoopField) ; calls DestroyCursor } From 9d21b82efcf96502e1de4fa95820091d8a1addba Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 2 Jan 2022 00:30:59 -0500 Subject: [PATCH 128/492] Set cursors without braces. --- ImagePut (for v1).ahk | 6 ++---- ImagePut.ahk | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 9a37a8c3..ae5afec2 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1878,10 +1878,8 @@ class ImagePut { ; Set all 14 System Cursors. Must CopyImage 14 times as SetSystemCursor deletes the handle each time. Loop Parse, "32512,32513,32514,32515,32516,32642,32643,32644,32645,32646,32648,32649,32650,32651", % "," - { - hCursor := DllCall("CopyImage", "ptr", hIcon, "uint", 2, "int", 0, "int", 0, "uint", 0, "ptr") - DllCall("SetSystemCursor", "ptr", hCursor, "int", A_LoopField) ; calls DestroyCursor - } + if hCursor := DllCall("CopyImage", "ptr", hIcon, "uint", 2, "int", 0, "int", 0, "uint", 0, "ptr") + DllCall("SetSystemCursor", "ptr", hCursor, "int", A_LoopField) ; calls DestroyCursor ; Destroy the original hIcon. Same as DestroyCursor. DllCall("DestroyIcon", "ptr", hIcon) diff --git a/ImagePut.ahk b/ImagePut.ahk index 553d22b6..7db0a032 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1969,10 +1969,8 @@ else { ; Set all 14 System Cursors. Must CopyImage 14 times as SetSystemCursor deletes the handle each time. Loop Parse, "32512,32513,32514,32515,32516,32642,32643,32644,32645,32646,32648,32649,32650,32651", "," - { - hCursor := DllCall("CopyImage", "ptr", hIcon, "uint", 2, "int", 0, "int", 0, "uint", 0, "ptr") - DllCall("SetSystemCursor", "ptr", hCursor, "int", A_LoopField) ; calls DestroyCursor - } + if hCursor := DllCall("CopyImage", "ptr", hIcon, "uint", 2, "int", 0, "int", 0, "uint", 0, "ptr") + DllCall("SetSystemCursor", "ptr", hCursor, "int", A_LoopField) ; calls DestroyCursor ; Destroy the original hIcon. Same as DestroyCursor. DllCall("DestroyIcon", "ptr", hIcon) From ab8abd9f94c1b43b58862dc93c15d95da8d8cddf Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 2 Jan 2022 01:03:43 -0500 Subject: [PATCH 129/492] Rewrite cursors RegEx --- ImagePut (for v1).ahk | 6 +++--- ImagePut.ahk | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index ae5afec2..4a4b47bb 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -364,8 +364,8 @@ class ImagePut { return "wallpaper" ; A "cursor" is the name of a known cursor name. - if (image ~= "(?i)^(IDC|OCR)?_?(A_Cursor|AppStarting|Arrow|Cross|Help|IBeam|" - . "Icon|No|Size|SizeAll|SizeNESW|SizeNS|SizeNWSE|SizeWE|UpArrow|Wait|Unknown)$") + if (image ~= "(?i)^A_Cursor|Unknown|(IDC_)?(AppStarting|Arrow|Cross|Hand|Help|IBeam|No| + . "SizeAll|SizeNESW|SizeNS|SizeNWSE|SizeWE|UpArrow|Wait)$") return "cursor" ; A "pdf" is either a file or url with a .pdf extension. @@ -1877,7 +1877,7 @@ class ImagePut { } ; Set all 14 System Cursors. Must CopyImage 14 times as SetSystemCursor deletes the handle each time. - Loop Parse, "32512,32513,32514,32515,32516,32642,32643,32644,32645,32646,32648,32649,32650,32651", % "," + Loop Parse, % "32512,32513,32514,32515,32516,32642,32643,32644,32645,32646,32648,32649,32650,32651", % "," if hCursor := DllCall("CopyImage", "ptr", hIcon, "uint", 2, "int", 0, "int", 0, "uint", 0, "ptr") DllCall("SetSystemCursor", "ptr", hCursor, "int", A_LoopField) ; calls DestroyCursor diff --git a/ImagePut.ahk b/ImagePut.ahk index 7db0a032..5223af2d 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -364,8 +364,8 @@ class ImagePut { return "wallpaper" ; A "cursor" is the name of a known cursor name. - if (image ~= "(?i)^(IDC|OCR)?_?(A_Cursor|AppStarting|Arrow|Cross|Help|IBeam|" - . "Icon|No|Size|SizeAll|SizeNESW|SizeNS|SizeNWSE|SizeWE|UpArrow|Wait|Unknown)$") + if (image ~= "(?i)^A_Cursor|Unknown|(IDC_)?(AppStarting|Arrow|Cross|Hand|Help|IBeam|No| + . "SizeAll|SizeNESW|SizeNS|SizeNWSE|SizeWE|UpArrow|Wait)$") return "cursor" ; A "pdf" is either a file or url with a .pdf extension. From df83ab16cc0d8033a41f790fdba240d62666cf75 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 2 Jan 2022 01:11:59 -0500 Subject: [PATCH 130/492] Add new Win10 cursors IDC_Pin and IDC_Person --- ImagePut (for v1).ahk | 11 ++++++----- ImagePut.ahk | 11 ++++++----- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 4a4b47bb..7304ae8b 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -364,8 +364,8 @@ class ImagePut { return "wallpaper" ; A "cursor" is the name of a known cursor name. - if (image ~= "(?i)^A_Cursor|Unknown|(IDC_)?(AppStarting|Arrow|Cross|Hand|Help|IBeam|No| - . "SizeAll|SizeNESW|SizeNS|SizeNWSE|SizeWE|UpArrow|Wait)$") + if (image ~= "(?i)^A_Cursor|Unknown|(IDC_)?(AppStarting|Arrow|Cross|Hand|Help| + . "IBeam|No|Pin|Person|SizeAll|SizeNESW|SizeNS|SizeNWSE|SizeWE|UpArrow|Wait)$") return "cursor" ; A "pdf" is either a file or url with a .pdf extension. @@ -1876,10 +1876,11 @@ class ImagePut { DllCall("DeleteObject", "ptr", NumGet(ii, 8+2*A_PtrSize, "ptr")) ; hbmColor } - ; Set all 14 System Cursors. Must CopyImage 14 times as SetSystemCursor deletes the handle each time. - Loop Parse, % "32512,32513,32514,32515,32516,32642,32643,32644,32645,32646,32648,32649,32650,32651", % "," + ; Set all 16 System Cursors. Must copy 16 times as SetSystemCursor deletes the handle each time. + Loop Parse, % "32512,32513,32514,32515,32516,32642,32643,32644,32645,32646,32648,32649,32650,32651,32671,32672", % "," if hCursor := DllCall("CopyImage", "ptr", hIcon, "uint", 2, "int", 0, "int", 0, "uint", 0, "ptr") - DllCall("SetSystemCursor", "ptr", hCursor, "int", A_LoopField) ; calls DestroyCursor + if !DllCall("SetSystemCursor", "ptr", hCursor, "int", A_LoopField) ; calls DestroyCursor + DllCall("DestroyCursor", "ptr", hCursor) ; Destroy the original hIcon. Same as DestroyCursor. DllCall("DestroyIcon", "ptr", hIcon) diff --git a/ImagePut.ahk b/ImagePut.ahk index 5223af2d..01822689 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -364,8 +364,8 @@ class ImagePut { return "wallpaper" ; A "cursor" is the name of a known cursor name. - if (image ~= "(?i)^A_Cursor|Unknown|(IDC_)?(AppStarting|Arrow|Cross|Hand|Help|IBeam|No| - . "SizeAll|SizeNESW|SizeNS|SizeNWSE|SizeWE|UpArrow|Wait)$") + if (image ~= "(?i)^A_Cursor|Unknown|(IDC_)?(AppStarting|Arrow|Cross|Hand|Help| + . "IBeam|No|Pin|Person|SizeAll|SizeNESW|SizeNS|SizeNWSE|SizeWE|UpArrow|Wait)$") return "cursor" ; A "pdf" is either a file or url with a .pdf extension. @@ -1967,10 +1967,11 @@ else { DllCall("DeleteObject", "ptr", NumGet(ii, 8+2*A_PtrSize, "ptr")) ; hbmColor } - ; Set all 14 System Cursors. Must CopyImage 14 times as SetSystemCursor deletes the handle each time. - Loop Parse, "32512,32513,32514,32515,32516,32642,32643,32644,32645,32646,32648,32649,32650,32651", "," + ; Set all 16 System Cursors. Must copy 16 times as SetSystemCursor deletes the handle each time. + Loop Parse, "32512,32513,32514,32515,32516,32642,32643,32644,32645,32646,32648,32649,32650,32651,32671,32672", "," if hCursor := DllCall("CopyImage", "ptr", hIcon, "uint", 2, "int", 0, "int", 0, "uint", 0, "ptr") - DllCall("SetSystemCursor", "ptr", hCursor, "int", A_LoopField) ; calls DestroyCursor + if !DllCall("SetSystemCursor", "ptr", hCursor, "int", A_LoopField) ; calls DestroyCursor + DllCall("DestroyCursor", "ptr", hCursor) ; Destroy the original hIcon. Same as DestroyCursor. DllCall("DestroyIcon", "ptr", hIcon) From 78672c1d8b4b9daf65d24f2b9e1a5eb215ba82b9 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 2 Jan 2022 11:31:19 -0500 Subject: [PATCH 131/492] Add Handwriting Cursor --- ImagePut (for v1).ahk | 8 ++++---- ImagePut.ahk | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 7304ae8b..8b445caf 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -364,8 +364,8 @@ class ImagePut { return "wallpaper" ; A "cursor" is the name of a known cursor name. - if (image ~= "(?i)^A_Cursor|Unknown|(IDC_)?(AppStarting|Arrow|Cross|Hand|Help| - . "IBeam|No|Pin|Person|SizeAll|SizeNESW|SizeNS|SizeNWSE|SizeWE|UpArrow|Wait)$") + if (image ~= "(?i)^A_Cursor|Unknown|(IDC_)?(AppStarting|Arrow|Cross|Hand(writing)?|" + . "Help|IBeam|No|Pin|Person|SizeAll|SizeNESW|SizeNS|SizeNWSE|SizeWE|UpArrow|Wait)$") return "cursor" ; A "pdf" is either a file or url with a .pdf extension. @@ -1876,8 +1876,8 @@ class ImagePut { DllCall("DeleteObject", "ptr", NumGet(ii, 8+2*A_PtrSize, "ptr")) ; hbmColor } - ; Set all 16 System Cursors. Must copy 16 times as SetSystemCursor deletes the handle each time. - Loop Parse, % "32512,32513,32514,32515,32516,32642,32643,32644,32645,32646,32648,32649,32650,32651,32671,32672", % "," + ; Set all 17 System Cursors. Must copy 17 times as SetSystemCursor deletes the handle each time. + Loop Parse, % "32512,32513,32514,32515,32516,32631,32642,32643,32644,32645,32646,32648,32649,32650,32651,32671,32672", % "," if hCursor := DllCall("CopyImage", "ptr", hIcon, "uint", 2, "int", 0, "int", 0, "uint", 0, "ptr") if !DllCall("SetSystemCursor", "ptr", hCursor, "int", A_LoopField) ; calls DestroyCursor DllCall("DestroyCursor", "ptr", hCursor) diff --git a/ImagePut.ahk b/ImagePut.ahk index 01822689..7f1136a7 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -364,8 +364,8 @@ class ImagePut { return "wallpaper" ; A "cursor" is the name of a known cursor name. - if (image ~= "(?i)^A_Cursor|Unknown|(IDC_)?(AppStarting|Arrow|Cross|Hand|Help| - . "IBeam|No|Pin|Person|SizeAll|SizeNESW|SizeNS|SizeNWSE|SizeWE|UpArrow|Wait)$") + if (image ~= "(?i)^A_Cursor|Unknown|(IDC_)?(AppStarting|Arrow|Cross|Hand(writing)?|" + . "Help|IBeam|No|Pin|Person|SizeAll|SizeNESW|SizeNS|SizeNWSE|SizeWE|UpArrow|Wait)$") return "cursor" ; A "pdf" is either a file or url with a .pdf extension. @@ -1967,8 +1967,8 @@ else { DllCall("DeleteObject", "ptr", NumGet(ii, 8+2*A_PtrSize, "ptr")) ; hbmColor } - ; Set all 16 System Cursors. Must copy 16 times as SetSystemCursor deletes the handle each time. - Loop Parse, "32512,32513,32514,32515,32516,32642,32643,32644,32645,32646,32648,32649,32650,32651,32671,32672", "," + ; Set all 17 System Cursors. Must copy 17 times as SetSystemCursor deletes the handle each time. + Loop Parse, "32512,32513,32514,32515,32516,32631,32642,32643,32644,32645,32646,32648,32649,32650,32651,32671,32672", "," if hCursor := DllCall("CopyImage", "ptr", hIcon, "uint", 2, "int", 0, "int", 0, "uint", 0, "ptr") if !DllCall("SetSystemCursor", "ptr", hCursor, "int", A_LoopField) ; calls DestroyCursor DllCall("DestroyCursor", "ptr", hCursor) From 90175db330ef0a1ee6d84c44303982eefc39c600 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 2 Jan 2022 12:16:05 -0500 Subject: [PATCH 132/492] Prioritize hex and base64 before handles & pointers --- ImagePut (for v1).ahk | 271 +++++++++++++++++++++--------------------- ImagePut.ahk | 271 +++++++++++++++++++++--------------------- 2 files changed, 272 insertions(+), 270 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 8b445caf..d8a51802 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -268,6 +268,16 @@ class ImagePut { return "file" } + if ObjHasKey(image, "hex") { + image := image.hex + return "hex" + } + + if ObjHasKey(image, "base64") { + image := image.base64 + return "base64" + } + if ObjHasKey(image, "monitor") { image := image.monitor return "monitor" @@ -303,16 +313,6 @@ class ImagePut { return "RandomAccessStream" } - if ObjHasKey(image, "hex") { - image := image.hex - return "hex" - } - - if ObjHasKey(image, "base64") { - image := image.base64 - return "base64" - } - if ObjHasKey(image, "sprite") { image := image.sprite return "sprite" @@ -380,6 +380,15 @@ class ImagePut { if FileExist(image) return "file" + ; A "hex" string is binary image data encoded into text using hexadecimal. + if (StrLen(image) >= 116) && (image ~= "(?i)^\s*(0x)?[0-9a-f]+\s*$") + return "hex" + + ; A "base64" string is binary image data encoded into text using standard 64 characters. + if (StrLen(image) >= 80) && (image ~= "^\s*(?:data:image\/[a-z]+;base64,)?" + . "(?:[A-Za-z0-9+\/]{4})*+(?:[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{2}==)?\s*$") + return "base64" + if (image ~= "^-?\d+$") { SysGet MonitorGetCount, MonitorCount ; A non-zero "monitor" number identifies each display uniquely; and 0 refers to the entire virtual screen. if (image >= 0 && image <= MonitorGetCount) @@ -414,14 +423,6 @@ class ImagePut { try if ComObjQuery(image, "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}") return "RandomAccessStream", ObjRelease(image) } - ; A "hex" string is binary image data encoded into text using hexadecimal. - if (StrLen(image) >= 116) && (image ~= "(?i)^\s*(0x)?[0-9a-f]+\s*$") - return "hex" - - ; A "base64" string is binary image data encoded into text using only 64 characters. - if (StrLen(image) >= 80) && (image ~= "^\s*(?:data:image\/[a-z]+;base64,)?" - . "(?:[A-Za-z0-9+\/]{4})*+(?:[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{2}==)?\s*$") - return "base64" ; For more helpful error messages: Catch file names without extensions! @@ -470,6 +471,12 @@ class ImagePut { if (type = "file") return this.from_file(image) + if (type = "hex") + return this.from_hex(image) + + if (type = "base64") + return this.from_base64(image) + if (type = "monitor") return this.from_monitor(image) @@ -491,12 +498,6 @@ class ImagePut { if (type = "RandomAccessStream") return this.from_RandomAccessStream(image) - if (type = "hex") - return this.from_hex(image) - - if (type = "base64") - return this.from_base64(image) - if (type = "sprite") return this.from_sprite(image) @@ -540,6 +541,14 @@ class ImagePut { if (cotype = "file") return this.put_file(pBitmap, p1, p2) + ; BitmapToCoimage("hex", pBitmap, extension, quality) + if (cotype = "hex") + return this.put_hex(pBitmap, p1, p2) + + ; BitmapToCoimage("base64", pBitmap, extension, quality) + if (cotype = "base64") + return this.put_base64(pBitmap, p1, p2) + ; BitmapToCoimage("dc", pBitmap, alpha) if (cotype = "dc") return this.put_dc(pBitmap, p1) @@ -564,14 +573,6 @@ class ImagePut { if (cotype = "RandomAccessStream") return this.put_RandomAccessStream(pBitmap, p1, p2) - ; BitmapToCoimage("hex", pBitmap, extension, quality) - if (cotype = "hex") - return this.put_hex(pBitmap, p1, p2) - - ; BitmapToCoimage("base64", pBitmap, extension, quality) - if (cotype = "base64") - return this.put_base64(pBitmap, p1, p2) - throw Exception("Conversion from bitmap to " cotype " is not supported.") } @@ -589,18 +590,18 @@ class ImagePut { if (type = "file") return this.get_file(image) - if (type = "stream") - return this.get_stream(image) - - if (type = "RandomAccessStream") - return this.get_RandomAccessStream(image) - if (type = "hex") return this.get_hex(image) if (type = "base64") return this.get_base64(image) + if (type = "stream") + return this.get_stream(image) + + if (type = "RandomAccessStream") + return this.get_RandomAccessStream(image) + throw Exception("Conversion from " type " to stream is not supported.") } @@ -609,14 +610,6 @@ class ImagePut { if (cotype = "file") return this.set_file(pStream, p1) - ; StreamToCoimage("stream", pStream) - if (cotype = "stream") - return pStream - - ; StreamToCoimage("RandomAccessStream", pStream) - if (cotype = "RandomAccessStream") - return this.set_RandomAccessStream(pStream) - ; StreamToCoimage("hex", pStream) if (cotype = "hex") return this.set_hex(pStream) @@ -625,6 +618,14 @@ class ImagePut { if (cotype = "base64") return this.set_base64(pStream) + ; StreamToCoimage("stream", pStream) + if (cotype = "stream") + return pStream + + ; StreamToCoimage("RandomAccessStream", pStream) + if (cotype = "RandomAccessStream") + return this.set_RandomAccessStream(pStream) + throw Exception("Conversion from stream to " cotype " is not supported.") } @@ -1191,6 +1192,49 @@ class ImagePut { return pStream } + from_hex(image) { + pStream := this.get_hex(image) + DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", pBitmap:=0) + ObjRelease(pStream) + return pBitmap + } + + get_hex(image) { + image := Trim(image) + image := RegExReplace(image, "^(0[xX])") + return this.get_string(image, 0xC) ; CRYPT_STRING_HEXRAW + } + + from_base64(image) { + pStream := this.get_base64(image) + DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", pBitmap:=0) + ObjRelease(pStream) + return pBitmap + } + + get_base64(image) { + image := Trim(image) + image := RegExReplace(image, "^data:image\/[a-z]+;base64,") + return this.get_string(image, 0x1) ; CRYPT_STRING_BASE64 + } + + get_string(image, flags) { + ; Ask for the size. Then allocate movable memory, copy to the buffer, unlock, and create stream. + DllCall("crypt32\CryptStringToBinary" + , "ptr", &image, "uint", 0, "uint", flags, "ptr", 0, "uint*", size:=0, "ptr", 0, "ptr", 0) + + hData := DllCall("GlobalAlloc", "uint", 0x2, "uptr", size, "ptr") + pData := DllCall("GlobalLock", "ptr", hData, "ptr") + + DllCall("crypt32\CryptStringToBinary" + , "ptr", &image, "uint", 0, "uint", flags, "ptr", pData, "uint*", size, "ptr", 0, "ptr", 0) + + DllCall("GlobalUnlock", "ptr", hData) + DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", true, "ptr*", pStream:=0, "uint") + + return pStream + } + from_monitor(image) { if (image > 0) { SysGet _, Monitor, image @@ -1394,49 +1438,6 @@ class ImagePut { return pStream } - from_hex(image) { - pStream := this.get_hex(image) - DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", pBitmap:=0) - ObjRelease(pStream) - return pBitmap - } - - get_hex(image) { - image := Trim(image) - image := RegExReplace(image, "^(0[xX])") - return this.get_string(image, 0xC) ; CRYPT_STRING_HEXRAW - } - - from_base64(image) { - pStream := this.get_base64(image) - DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", pBitmap:=0) - ObjRelease(pStream) - return pBitmap - } - - get_base64(image) { - image := Trim(image) - image := RegExReplace(image, "^data:image\/[a-z]+;base64,") - return this.get_string(image, 0x1) ; CRYPT_STRING_BASE64 - } - - get_string(image, flags) { - ; Ask for the size. Then allocate movable memory, copy to the buffer, unlock, and create stream. - DllCall("crypt32\CryptStringToBinary" - , "ptr", &image, "uint", 0, "uint", flags, "ptr", 0, "uint*", size:=0, "ptr", 0, "ptr", 0) - - hData := DllCall("GlobalAlloc", "uint", 0x2, "uptr", size, "ptr") - pData := DllCall("GlobalLock", "ptr", hData, "ptr") - - DllCall("crypt32\CryptStringToBinary" - , "ptr", &image, "uint", 0, "uint", flags, "ptr", pData, "uint*", size, "ptr", 0, "ptr", 0) - - DllCall("GlobalUnlock", "ptr", hData) - DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", true, "ptr*", pStream:=0, "uint") - - return pStream - } - from_sprite(image) { ; Create a source pBitmap and extract the width and height. if DllCall("gdiplus\GdipCreateBitmapFromFile", "wstr", image, "ptr*", sBitmap:=0) @@ -1930,6 +1931,52 @@ class ImagePut { return filepath } + put_hex(pBitmap, extension := "", quality := "") { + ; Default extension is PNG for small sizes! + if (extension == "") + extension := "png" + + pStream := this.put_stream(pBitmap, extension, quality) + hex := this.set_hex(pStream) + ObjRelease(pStream) + return hex + } + + set_hex(pStream) { + return this.set_string(pStream, 0x4000000C) ; CRYPT_STRING_NOCRLF | CRYPT_STRING_HEXRAW + } + + put_base64(pBitmap, extension := "", quality := "") { + ; Default extension is PNG for small sizes! + if (extension == "") + extension := "png" + + pStream := this.put_stream(pBitmap, extension, quality) + base64 := this.set_base64(pStream) + ObjRelease(pStream) + return base64 + } + + set_base64(pStream) { + return this.set_string(pStream, 0x40000001) ; CRYPT_STRING_NOCRLF | CRYPT_STRING_BASE64 + } + + set_string(pStream, flags) { + ; Thanks noname - https://www.autohotkey.com/boards/viewtopic.php?style=7&p=144247#p144247 + + ; For compatibility with SHCreateMemStream do not use GetHGlobalFromStream. + DllCall("shlwapi\IStream_Size", "ptr", pStream, "ptr*", size:=0, "uint") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") + DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", &bin := VarSetCapacity(bin, size), "uint", size, "uint") + + ; Using CryptBinaryToStringA saves about 2MB in memory. + DllCall("crypt32\CryptBinaryToStringA", "ptr", &bin, "uint", size, "uint", flags, "ptr", 0, "uint*", length:=0) + VarSetCapacity(str, length) + DllCall("crypt32\CryptBinaryToStringA", "ptr", &bin, "uint", size, "uint", flags, "ptr", &str, "uint*", length) + + return StrGet(&str, length, "CP0") + } + put_dc(pBitmap, alpha := "") { ; This may seem strange, but the hBitmap is selected onto the device context, ; and therefore cannot be deleted. In addition, the stock bitmap can never be leaked. @@ -2023,52 +2070,6 @@ class ImagePut { return pRandomAccessStream } - put_hex(pBitmap, extension := "", quality := "") { - ; Default extension is PNG for small sizes! - if (extension == "") - extension := "png" - - pStream := this.put_stream(pBitmap, extension, quality) - hex := this.set_hex(pStream) - ObjRelease(pStream) - return hex - } - - set_hex(pStream) { - return this.set_string(pStream, 0x4000000C) ; CRYPT_STRING_NOCRLF | CRYPT_STRING_HEXRAW - } - - put_base64(pBitmap, extension := "", quality := "") { - ; Default extension is PNG for small sizes! - if (extension == "") - extension := "png" - - pStream := this.put_stream(pBitmap, extension, quality) - base64 := this.set_base64(pStream) - ObjRelease(pStream) - return base64 - } - - set_base64(pStream) { - return this.set_string(pStream, 0x40000001) ; CRYPT_STRING_NOCRLF | CRYPT_STRING_BASE64 - } - - set_string(pStream, flags) { - ; Thanks noname - https://www.autohotkey.com/boards/viewtopic.php?style=7&p=144247#p144247 - - ; For compatibility with SHCreateMemStream do not use GetHGlobalFromStream. - DllCall("shlwapi\IStream_Size", "ptr", pStream, "ptr*", size:=0, "uint") - DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") - DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", &bin := VarSetCapacity(bin, size), "uint", size, "uint") - - ; Using CryptBinaryToStringA saves about 2MB in memory. - DllCall("crypt32\CryptBinaryToStringA", "ptr", &bin, "uint", size, "uint", flags, "ptr", 0, "uint*", length:=0) - VarSetCapacity(str, length) - DllCall("crypt32\CryptBinaryToStringA", "ptr", &bin, "uint", size, "uint", flags, "ptr", &str, "uint*", length) - - return StrGet(&str, length, "CP0") - } - select_codec(pBitmap, extension, quality, ByRef pCodec, ByRef ep, ByRef ci, ByRef v) { ; Fill a buffer with the available image codec info. DllCall("gdiplus\GdipGetImageEncodersSize", "uint*", count:=0, "uint*", size:=0) diff --git a/ImagePut.ahk b/ImagePut.ahk index 7f1136a7..79e7c73b 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -268,6 +268,16 @@ class ImagePut { return "file" } + if ObjHasOwnProp(image, "hex") { + image := image.hex + return "hex" + } + + if ObjHasOwnProp(image, "base64") { + image := image.base64 + return "base64" + } + if ObjHasOwnProp(image, "monitor") { image := image.monitor return "monitor" @@ -303,16 +313,6 @@ class ImagePut { return "RandomAccessStream" } - if ObjHasOwnProp(image, "hex") { - image := image.hex - return "hex" - } - - if ObjHasOwnProp(image, "base64") { - image := image.base64 - return "base64" - } - if ObjHasOwnProp(image, "sprite") { image := image.sprite return "sprite" @@ -380,6 +380,15 @@ class ImagePut { if FileExist(image) return "file" + ; A "hex" string is binary image data encoded into text using hexadecimal. + if (StrLen(image) >= 116) && (image ~= "(?i)^\s*(0x)?[0-9a-f]+\s*$") + return "hex" + + ; A "base64" string is binary image data encoded into text using standard 64 characters. + if (StrLen(image) >= 80) && (image ~= "^\s*(?:data:image\/[a-z]+;base64,)?" + . "(?:[A-Za-z0-9+\/]{4})*+(?:[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{2}==)?\s*$") + return "base64" + if (image ~= "^-?\d+$") { ; A non-zero "monitor" number identifies each display uniquely; and 0 refers to the entire virtual screen. if (image >= 0 && image <= MonitorGetCount()) @@ -414,14 +423,6 @@ class ImagePut { try if ComObjQuery(image, "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}") return "RandomAccessStream" } - ; A "hex" string is binary image data encoded into text using hexadecimal. - if (StrLen(image) >= 116) && (image ~= "(?i)^\s*(0x)?[0-9a-f]+\s*$") - return "hex" - - ; A "base64" string is binary image data encoded into text using only 64 characters. - if (StrLen(image) >= 80) && (image ~= "^\s*(?:data:image\/[a-z]+;base64,)?" - . "(?:[A-Za-z0-9+\/]{4})*+(?:[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{2}==)?\s*$") - return "base64" ; For more helpful error messages: Catch file names without extensions! @@ -470,6 +471,12 @@ class ImagePut { if (type = "file") return this.from_file(image) + if (type = "hex") + return this.from_hex(image) + + if (type = "base64") + return this.from_base64(image) + if (type = "monitor") return this.from_monitor(image) @@ -491,12 +498,6 @@ class ImagePut { if (type = "RandomAccessStream") return this.from_RandomAccessStream(image) - if (type = "hex") - return this.from_hex(image) - - if (type = "base64") - return this.from_base64(image) - if (type = "sprite") return this.from_sprite(image) @@ -540,6 +541,14 @@ class ImagePut { if (cotype = "file") return this.put_file(pBitmap, p1, p2) + ; BitmapToCoimage("hex", pBitmap, extension, quality) + if (cotype = "hex") + return this.put_hex(pBitmap, p1, p2) + + ; BitmapToCoimage("base64", pBitmap, extension, quality) + if (cotype = "base64") + return this.put_base64(pBitmap, p1, p2) + ; BitmapToCoimage("dc", pBitmap, alpha) if (cotype = "dc") return this.put_dc(pBitmap, p1) @@ -564,14 +573,6 @@ class ImagePut { if (cotype = "RandomAccessStream") return this.put_RandomAccessStream(pBitmap, p1, p2) - ; BitmapToCoimage("hex", pBitmap, extension, quality) - if (cotype = "hex") - return this.put_hex(pBitmap, p1, p2) - - ; BitmapToCoimage("base64", pBitmap, extension, quality) - if (cotype = "base64") - return this.put_base64(pBitmap, p1, p2) - throw Error("Conversion from bitmap to " cotype " is not supported.") } @@ -589,18 +590,18 @@ class ImagePut { if (type = "file") return this.get_file(image) - if (type = "stream") - return this.get_stream(image) - - if (type = "RandomAccessStream") - return this.get_RandomAccessStream(image) - if (type = "hex") return this.get_hex(image) if (type = "base64") return this.get_base64(image) + if (type = "stream") + return this.get_stream(image) + + if (type = "RandomAccessStream") + return this.get_RandomAccessStream(image) + throw Error("Conversion from " type " to stream is not supported.") } @@ -609,14 +610,6 @@ class ImagePut { if (cotype = "file") return this.set_file(pStream, p1) - ; StreamToCoimage("stream", pStream) - if (cotype = "stream") - return pStream - - ; StreamToCoimage("RandomAccessStream", pStream) - if (cotype = "RandomAccessStream") - return this.set_RandomAccessStream(pStream) - ; StreamToCoimage("hex", pStream) if (cotype = "hex") return this.set_hex(pStream) @@ -625,6 +618,14 @@ class ImagePut { if (cotype = "base64") return this.set_base64(pStream) + ; StreamToCoimage("stream", pStream) + if (cotype = "stream") + return pStream + + ; StreamToCoimage("RandomAccessStream", pStream) + if (cotype = "RandomAccessStream") + return this.set_RandomAccessStream(pStream) + throw Error("Conversion from stream to " cotype " is not supported.") } @@ -1191,6 +1192,49 @@ class ImagePut { return pStream } + static from_hex(image) { + pStream := this.get_hex(image) + DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", &pBitmap:=0) + ObjRelease(pStream) + return pBitmap + } + + static get_hex(image) { + image := Trim(image) + image := RegExReplace(image, "^(0[xX])") + return this.get_string(image, 0xC) ; CRYPT_STRING_HEXRAW + } + + static from_base64(image) { + pStream := this.get_base64(image) + DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", &pBitmap:=0) + ObjRelease(pStream) + return pBitmap + } + + static get_base64(image) { + image := Trim(image) + image := RegExReplace(image, "^data:image\/[a-z]+;base64,") + return this.get_string(image, 0x1) ; CRYPT_STRING_BASE64 + } + + static get_string(image, flags) { + ; Ask for the size. Then allocate movable memory, copy to the buffer, unlock, and create stream. + DllCall("crypt32\CryptStringToBinary" + , "ptr", StrPtr(image), "uint", 0, "uint", flags, "ptr", 0, "uint*", &size:=0, "ptr", 0, "ptr", 0) + + hData := DllCall("GlobalAlloc", "uint", 0x2, "uptr", size, "ptr") + pData := DllCall("GlobalLock", "ptr", hData, "ptr") + + DllCall("crypt32\CryptStringToBinary" + , "ptr", StrPtr(image), "uint", 0, "uint", flags, "ptr", pData, "uint*", size, "ptr", 0, "ptr", 0) + + DllCall("GlobalUnlock", "ptr", hData) + DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", true, "ptr*", &pStream:=0, "HRESULT") + + return pStream + } + static from_monitor(image) { if (image > 0) { MonitorGet(image, &Left, &Top, &Right, &Bottom) @@ -1394,49 +1438,6 @@ class ImagePut { return pStream } - static from_hex(image) { - pStream := this.get_hex(image) - DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", &pBitmap:=0) - ObjRelease(pStream) - return pBitmap - } - - static get_hex(image) { - image := Trim(image) - image := RegExReplace(image, "^(0[xX])") - return this.get_string(image, 0xC) ; CRYPT_STRING_HEXRAW - } - - static from_base64(image) { - pStream := this.get_base64(image) - DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", &pBitmap:=0) - ObjRelease(pStream) - return pBitmap - } - - static get_base64(image) { - image := Trim(image) - image := RegExReplace(image, "^data:image\/[a-z]+;base64,") - return this.get_string(image, 0x1) ; CRYPT_STRING_BASE64 - } - - static get_string(image, flags) { - ; Ask for the size. Then allocate movable memory, copy to the buffer, unlock, and create stream. - DllCall("crypt32\CryptStringToBinary" - , "ptr", StrPtr(image), "uint", 0, "uint", flags, "ptr", 0, "uint*", &size:=0, "ptr", 0, "ptr", 0) - - hData := DllCall("GlobalAlloc", "uint", 0x2, "uptr", size, "ptr") - pData := DllCall("GlobalLock", "ptr", hData, "ptr") - - DllCall("crypt32\CryptStringToBinary" - , "ptr", StrPtr(image), "uint", 0, "uint", flags, "ptr", pData, "uint*", size, "ptr", 0, "ptr", 0) - - DllCall("GlobalUnlock", "ptr", hData) - DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", true, "ptr*", &pStream:=0, "HRESULT") - - return pStream - } - static from_sprite(image) { ; Create a source pBitmap and extract the width and height. if DllCall("gdiplus\GdipCreateBitmapFromFile", "wstr", image, "ptr*", &sBitmap:=0) @@ -2021,6 +2022,52 @@ else { return filepath } + static put_hex(pBitmap, extension := "", quality := "") { + ; Default extension is PNG for small sizes! + if (extension == "") + extension := "png" + + pStream := this.put_stream(pBitmap, extension, quality) + hex := this.set_hex(pStream) + ObjRelease(pStream) + return hex + } + + static set_hex(pStream) { + return this.set_string(pStream, 0x4000000C) ; CRYPT_STRING_NOCRLF | CRYPT_STRING_HEXRAW + } + + static put_base64(pBitmap, extension := "", quality := "") { + ; Default extension is PNG for small sizes! + if (extension == "") + extension := "png" + + pStream := this.put_stream(pBitmap, extension, quality) + base64 := this.set_base64(pStream) + ObjRelease(pStream) + return base64 + } + + static set_base64(pStream) { + return this.set_string(pStream, 0x40000001) ; CRYPT_STRING_NOCRLF | CRYPT_STRING_BASE64 + } + + static set_string(pStream, flags) { + ; Thanks noname - https://www.autohotkey.com/boards/viewtopic.php?style=7&p=144247#p144247 + + ; For compatibility with SHCreateMemStream do not use GetHGlobalFromStream. + DllCall("shlwapi\IStream_Size", "ptr", pStream, "ptr*", &size:=0, "HRESULT") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") + DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", bin := Buffer(size), "uint", size, "HRESULT") + + ; Using CryptBinaryToStringA saves about 2MB in memory. + DllCall("crypt32\CryptBinaryToStringA", "ptr", bin, "uint", size, "uint", flags, "ptr", 0, "uint*", &length:=0) + str := Buffer(length) + DllCall("crypt32\CryptBinaryToStringA", "ptr", bin, "uint", size, "uint", flags, "ptr", str, "uint*", length) + + return StrGet(str, length, "CP0") + } + static put_dc(pBitmap, alpha := "") { ; This may seem strange, but the hBitmap is selected onto the device context, ; and therefore cannot be deleted. In addition, the stock bitmap can never be leaked. @@ -2114,52 +2161,6 @@ else { return pRandomAccessStream } - static put_hex(pBitmap, extension := "", quality := "") { - ; Default extension is PNG for small sizes! - if (extension == "") - extension := "png" - - pStream := this.put_stream(pBitmap, extension, quality) - hex := this.set_hex(pStream) - ObjRelease(pStream) - return hex - } - - static set_hex(pStream) { - return this.set_string(pStream, 0x4000000C) ; CRYPT_STRING_NOCRLF | CRYPT_STRING_HEXRAW - } - - static put_base64(pBitmap, extension := "", quality := "") { - ; Default extension is PNG for small sizes! - if (extension == "") - extension := "png" - - pStream := this.put_stream(pBitmap, extension, quality) - base64 := this.set_base64(pStream) - ObjRelease(pStream) - return base64 - } - - static set_base64(pStream) { - return this.set_string(pStream, 0x40000001) ; CRYPT_STRING_NOCRLF | CRYPT_STRING_BASE64 - } - - static set_string(pStream, flags) { - ; Thanks noname - https://www.autohotkey.com/boards/viewtopic.php?style=7&p=144247#p144247 - - ; For compatibility with SHCreateMemStream do not use GetHGlobalFromStream. - DllCall("shlwapi\IStream_Size", "ptr", pStream, "ptr*", &size:=0, "HRESULT") - DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") - DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", bin := Buffer(size), "uint", size, "HRESULT") - - ; Using CryptBinaryToStringA saves about 2MB in memory. - DllCall("crypt32\CryptBinaryToStringA", "ptr", bin, "uint", size, "uint", flags, "ptr", 0, "uint*", &length:=0) - str := Buffer(length) - DllCall("crypt32\CryptBinaryToStringA", "ptr", bin, "uint", size, "uint", flags, "ptr", str, "uint*", length) - - return StrGet(str, length, "CP0") - } - static select_codec(pBitmap, extension, quality, &pCodec, &ep, &ci, &v) { ; Fill a buffer with the available image codec info. DllCall("gdiplus\GdipGetImageEncodersSize", "uint*", &count:=0, "uint*", &size:=0) From e7f66fc6d057c7a99aa17ad7f0160d33a3104208 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 4 Jan 2022 12:42:51 -0500 Subject: [PATCH 133/492] Refactor ImageDestroy into its own class --- ImagePut (for v1).ahk | 131 +++++++++++++++++++++++------------------- ImagePut.ahk | 129 ++++++++++++++++++++++------------------- 2 files changed, 141 insertions(+), 119 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index d8a51802..28a1a2fc 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -104,15 +104,24 @@ ImagePutWindow(image, title := "") { return ImagePut("window", image, title) } -; A cleanup function for all images. -ImageDestroy(image) { - return ImagePut.Destroy(image) + + +ImageShow() { + return } ImagePut(cotype, image, p*) { return ImagePut.call(cotype, image, p*) } +ImageDestroy(image) { + return ImageDestroy.call(image) +} + +ImageEqual(images*) { + return ImageEqual.call(images*) +} + class ImagePut { @@ -629,60 +638,6 @@ class ImagePut { throw Exception("Conversion from stream to " cotype " is not supported.") } - Destroy(image) { - try type := this.DontVerifyImageType(image) - catch - type := this.ImageType(image) - - if (type = "clipboard") { - if !DllCall("OpenClipboard", "ptr", A_ScriptHwnd) - throw Exception("Clipboard could not be opened.") - return DllCall("EmptyClipboard"), DllCall("CloseClipboard") - } - - if (type = "screenshot") - return DllCall("InvalidateRect", "ptr", 0, "ptr", 0, "int", 0) - - if (type = "window") - return DllCall("DestroyWindow", "ptr", image) - - if (type = "wallpaper") - return DllCall("SystemParametersInfo", "uint", SPI_SETDESKWALLPAPER := 0x14, "uint", 0, "ptr", 0, "uint", 2) - - if (type = "cursor") - return DllCall("SystemParametersInfo", "uint", SPI_SETCURSORS := 0x57, "uint", 0, "ptr", 0, "uint", 0) - - if (type = "file") - FileDelete % image - - if (type = "dc") { - if (DllCall("GetObjectType", "ptr", image, "uint") == 3) { ; OBJ_DC - hwnd := DllCall("WindowFromDC", "ptr", image, "ptr") - DllCall("ReleaseDC", "ptr", hwnd, "ptr", image) - } - - if (DllCall("GetObjectType", "ptr", image, "uint") == 10) { ; OBJ_MEMDC - DllCall("DeleteDC", "ptr", image) - } - } - - if (type = "hBitmap") - return DllCall("DeleteObject", "ptr", image) - - if (type = "hIcon") - return DllCall("DestroyIcon", "ptr", image) - - if (type = "bitmap") - return !DllCall("gdiplus\GdipDisposeImage", "ptr", image) - - if (type = "RandomAccessStream") or (type = "stream") - return !ObjRelease(image) - } - - DisposeImage(pBitmap) { - return DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) - } - BitmapCrop(ByRef pBitmap, crop) { if not (IsObject(crop) && crop[1] ~= "^-?\d+(\.\d*)?%?$" && crop[2] ~= "^-?\d+(\.\d*)?%?$" @@ -2246,9 +2201,65 @@ class ImagePut { } ; End of ImagePut class. -ImageEqual(images*) { - return ImageEqual.call(images*) -} +class ImageDestroy extends ImagePut { + + call(image) { + this.gdiplusStartup() + try type := this.DontVerifyImageType(image) + catch + type := this.ImageType(image) + this.Destroy(type, image) + this.gdiplusShutdown() + return + } + + Destroy(type, image) { + if (type = "clipboard") { + if !DllCall("OpenClipboard", "ptr", A_ScriptHwnd) + throw Exception("Clipboard could not be opened.") + return DllCall("EmptyClipboard"), DllCall("CloseClipboard") + } + + if (type = "screenshot") + return DllCall("InvalidateRect", "ptr", 0, "ptr", 0, "int", 0) + + if (type = "window") + return DllCall("DestroyWindow", "ptr", image) + + if (type = "wallpaper") + return DllCall("SystemParametersInfo", "uint", SPI_SETDESKWALLPAPER := 0x14, "uint", 0, "ptr", 0, "uint", 2) + + if (type = "cursor") + return DllCall("SystemParametersInfo", "uint", SPI_SETCURSORS := 0x57, "uint", 0, "ptr", 0, "uint", 0) + + if (type = "file") + FileDelete % image + + if (type = "dc") { + if (DllCall("GetObjectType", "ptr", image, "uint") == 3) { ; OBJ_DC + hwnd := DllCall("WindowFromDC", "ptr", image, "ptr") + DllCall("ReleaseDC", "ptr", hwnd, "ptr", image) + } + + if (DllCall("GetObjectType", "ptr", image, "uint") == 10) { ; OBJ_MEMDC + DllCall("DeleteDC", "ptr", image) + } + } + + if (type = "hBitmap") + return DllCall("DeleteObject", "ptr", image) + + if (type = "hIcon") + return DllCall("DestroyIcon", "ptr", image) + + if (type = "bitmap") + return !DllCall("gdiplus\GdipDisposeImage", "ptr", image) + + if (type = "RandomAccessStream") or (type = "stream") + return !ObjRelease(image) + } +} ; End of ImageDestroy class. + class ImageEqual extends ImagePut { diff --git a/ImagePut.ahk b/ImagePut.ahk index 79e7c73b..9377327a 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -104,15 +104,24 @@ ImagePutWindow(image, title := "") { return ImagePut("window", image, title) } -; A cleanup function for all images. -ImageDestroy(image) { - return ImagePut.Destroy(image) -} - +ImageShow() { + return +} +/* +ImagePut(cotype, image, p*) { + return ImagePut.call(cotype, image, p*) +} +ImageDestroy(image) { + return ImageDestroy.call(image) +} +ImageEqual(images*) { + return ImageEqual.call(images*) +} +*/ class ImagePut { @@ -629,60 +638,6 @@ class ImagePut { throw Error("Conversion from stream to " cotype " is not supported.") } - static Destroy(image) { - try type := this.DontVerifyImageType(image) - catch - type := this.ImageType(image) - - if (type = "clipboard") { - if !DllCall("OpenClipboard", "ptr", A_ScriptHwnd) - throw Error("Clipboard could not be opened.") - return ((_,*)=>_)(DllCall("EmptyClipboard"), DllCall("CloseClipboard")) - } - - if (type = "screenshot") - return DllCall("InvalidateRect", "ptr", 0, "ptr", 0, "int", 0) - - if (type = "window") - return DllCall("DestroyWindow", "ptr", image) - - if (type = "wallpaper") - return DllCall("SystemParametersInfo", "uint", SPI_SETDESKWALLPAPER := 0x14, "uint", 0, "ptr", 0, "uint", 2) - - if (type = "cursor") - return DllCall("SystemParametersInfo", "uint", SPI_SETCURSORS := 0x57, "uint", 0, "ptr", 0, "uint", 0) - - if (type = "file") - FileDelete image - - if (type = "dc") { - if (DllCall("GetObjectType", "ptr", image, "uint") == 3) { ; OBJ_DC - hwnd := DllCall("WindowFromDC", "ptr", image, "ptr") - DllCall("ReleaseDC", "ptr", hwnd, "ptr", image) - } - - if (DllCall("GetObjectType", "ptr", image, "uint") == 10) { ; OBJ_MEMDC - DllCall("DeleteDC", "ptr", image) - } - } - - if (type = "hBitmap") - return DllCall("DeleteObject", "ptr", image) - - if (type = "hIcon") - return DllCall("DestroyIcon", "ptr", image) - - if (type = "bitmap") - return !DllCall("gdiplus\GdipDisposeImage", "ptr", image) - - if (type = "RandomAccessStream") or (type = "stream") - return !ObjRelease(image) - } - - static DisposeImage(pBitmap) { - return DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) - } - static BitmapCrop(&pBitmap, crop) { if not (IsObject(crop) && crop[1] ~= "^-?\d+(\.\d*)?%?$" && crop[2] ~= "^-?\d+(\.\d*)?%?$" @@ -2337,8 +2292,64 @@ else { } ; End of ImagePut class. +class ImageDestroy extends ImagePut { + + static call(image) { + this.gdiplusStartup() + try type := this.DontVerifyImageType(&image) + catch + type := this.ImageType(image) + this.Destroy(type, image) + this.gdiplusShutdown() + return + } + + static Destroy(type, image) { + if (type = "clipboard") { + if !DllCall("OpenClipboard", "ptr", A_ScriptHwnd) + throw Error("Clipboard could not be opened.") + return ((_,*)=>_)(DllCall("EmptyClipboard"), DllCall("CloseClipboard")) + } + + if (type = "screenshot") + return DllCall("InvalidateRect", "ptr", 0, "ptr", 0, "int", 0) + + if (type = "window") + return DllCall("DestroyWindow", "ptr", image) + if (type = "wallpaper") + return DllCall("SystemParametersInfo", "uint", SPI_SETDESKWALLPAPER := 0x14, "uint", 0, "ptr", 0, "uint", 2) + if (type = "cursor") + return DllCall("SystemParametersInfo", "uint", SPI_SETCURSORS := 0x57, "uint", 0, "ptr", 0, "uint", 0) + + if (type = "file") + FileDelete image + + if (type = "dc") { + if (DllCall("GetObjectType", "ptr", image, "uint") == 3) { ; OBJ_DC + hwnd := DllCall("WindowFromDC", "ptr", image, "ptr") + DllCall("ReleaseDC", "ptr", hwnd, "ptr", image) + } + + if (DllCall("GetObjectType", "ptr", image, "uint") == 10) { ; OBJ_MEMDC + DllCall("DeleteDC", "ptr", image) + } + } + + if (type = "hBitmap") + return DllCall("DeleteObject", "ptr", image) + + if (type = "hIcon") + return DllCall("DestroyIcon", "ptr", image) + + if (type = "bitmap") + return !DllCall("gdiplus\GdipDisposeImage", "ptr", image) + + if (type = "RandomAccessStream") or (type = "stream") + return !ObjRelease(image) + } +} ; End of ImageDestroy class. class ImageEqual extends ImagePut { From 97356e0c94e281910ebd0aca28066d158f9aa20b Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 4 Jan 2022 17:11:08 -0500 Subject: [PATCH 134/492] Clean up put_window --- ImagePut.ahk | 315 ++++++++++++++++++++++----------------------------- 1 file changed, 137 insertions(+), 178 deletions(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index 9377327a..0ade7615 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1555,66 +1555,124 @@ class ImagePut { static put_window(pBitmap, title := "", pos := "") { - WindowProc(hwnd, uMsg, wParam, lParam) { + ; Prevent the script from exiting early. + Persistent(true) - ; WM_DESTROY - if (uMsg = 0x2) { - return Persistent(false) - } + ; The class name is ImagePut. + cls := this.prototype.__class + wc := Buffer(A_PtrSize = 4 ? 48:80) ; sizeof(WNDCLASSEX) = 48, 80 + + ; Register the window class. + if !DllCall("GetClassInfoEx", "ptr", 0, "str", cls, "ptr", wc) { + + ; Create window data. + pWndProc := CallbackCreate(WindowProc) + hCursor := DllCall("LoadCursor", "ptr", 0, "ptr", 32512, "ptr") ; IDC_ARROW + hBrush := DllCall("GetStockObject", "int", 5, "ptr") ; Hollow_brush + + ; struct tagWNDCLASSEXA - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexa + ; struct tagWNDCLASSEXW - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexw + _ := (A_PtrSize = 4) + NumPut( "uint", wc.size, wc, 0) ; cbSize + NumPut( "uint", 0, wc, 4) ; style + NumPut( "ptr", pWndProc, wc, 8) ; lpfnWndProc + NumPut( "int", 0, wc, _ ? 12:16) ; cbClsExtra + NumPut( "int", 0, wc, _ ? 16:20) ; cbWndExtra + NumPut( "ptr", 0, wc, _ ? 20:24) ; hInstance + NumPut( "ptr", 0, wc, _ ? 24:32) ; hIcon + NumPut( "ptr", hCursor, wc, _ ? 28:40) ; hCursor + NumPut( "ptr", hBrush, wc, _ ? 32:48) ; hbrBackground + NumPut( "ptr", 0, wc, _ ? 36:56) ; lpszMenuName + NumPut( "ptr", StrPtr(cls), wc, _ ? 40:64) ; lpszClassName + NumPut( "ptr", 0, wc, _ ? 44:72) ; hIconSm + + ; Registers a window class for subsequent use in calls to the CreateWindow or CreateWindowEx function. + DllCall("RegisterClassEx", "ptr", wc, "ushort") + } - ; WM_LBUTTONDOWN - if (uMsg = 0x201) { - parent := DllCall("GetParent", "ptr", hwnd, "ptr") - hwnd := (parent != A_ScriptHwnd && parent != 0) ? parent : hwnd - return DllCall("DefWindowProc", "ptr", hwnd, "uint", 0xA1, "uptr", 2, "ptr", 0, "ptr") - } + ; Get Bitmap width and height. + DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) + DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) - ; WM_RBUTTONUP - if (uMsg = 0x205) { - parent := DllCall("GetParent", "ptr", hwnd, "ptr") - hwnd := (parent != A_ScriptHwnd && parent != 0) ? parent : hwnd - return DllCall("DestroyWindow", "ptr", hwnd) - } + ; If both dimensions exceed the screen boundaries, compare the aspect ratio of the image + ; to the aspect ratio of the screen to determine the scale factor. Default scale is 1. + s := (width > A_ScreenWidth) && (width / height > A_ScreenWidth / A_ScreenHeight) ? A_ScreenWidth / width + : (height > A_ScreenHeight) && (width / height <= A_ScreenWidth / A_ScreenHeight) ? A_ScreenHeight / height + : 1 - return DllCall("DefWindowProc", "ptr", hwnd, "uint", uMsg, "uptr", wParam, "ptr", lParam, "ptr") - } + w := IsObject(pos) && pos.has(3) ? pos[3] : s * width + h := IsObject(pos) && pos.has(4) ? pos[4] : s * height - ; Make it permanent. - Persistent(true) + x := IsObject(pos) && pos.has(1) ? pos[1] : 0.5*(A_ScreenWidth - w) + y := IsObject(pos) && pos.has(2) ? pos[2] : 0.5*(A_ScreenHeight - h) + ; Resolve dependent coordinates first, coordinates second, and distances last. + x2 := Round(x + w) + y2 := Round(y + h) + x := Round(x) + y := Round(y) + w := x2 - x + h := y2 - y - cls := this.prototype.__class - pWndProc := CallbackCreate(WindowProc) - - hCursor := DllCall("LoadCursor", "ptr", 0, "ptr", 32512, "ptr") ; IDC_ARROW - ;hBrush := DllCall("CreateSolidBrush", "uint", 0x00F0F0F0, "ptr") - hBrush := DllCall("GetStockObject", "int", 5, "ptr") ; Hollow_brush - - ; explanation or guess: There's 2 layers. The bottom layer is F0F0F0 and it is set to transparent. - ; However, transparency is click through. But if the hollow brush is used instead, it paints with - ; no color. But the system interprets that as the default color, F0F0F0. So later when F0F0F0 is made - ; transparent, it can't set the bounds as click though, because the system used the default color to - ; represent the empty color, and all we did was remove the system shading. (Just a guess.) - - ; struct tagWNDCLASSEXA - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexa - ; struct tagWNDCLASSEXW - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexw - _ := (A_PtrSize = 4) - wc := Buffer(_ ? 48:80) ; sizeof(WNDCLASSEX) = 48, 80 - NumPut( "uint", wc.size, wc, 0) ; cbSize - NumPut( "uint", 0, wc, 4) ; style - NumPut( "ptr", pWndProc, wc, 8) ; lpfnWndProc - NumPut( "int", 0, wc, _ ? 12:16) ; cbClsExtra - NumPut( "int", 0, wc, _ ? 16:20) ; cbWndExtra - NumPut( "ptr", 0, wc, _ ? 20:24) ; hInstance - NumPut( "ptr", 0, wc, _ ? 24:32) ; hIcon - NumPut( "ptr", hCursor, wc, _ ? 28:40) ; hCursor - NumPut( "ptr", hBrush, wc, _ ? 32:48) ; hbrBackground - NumPut( "ptr", 0, wc, _ ? 36:56) ; lpszMenuName - NumPut( "ptr", StrPtr(cls), wc, _ ? 40:64) ; lpszClassName - NumPut( "ptr", 0, wc, _ ? 44:72) ; hIconSm - - ; Registers a window class for subsequent use in calls to the CreateWindow or CreateWindowEx function. - DllCall("RegisterClassEx", "ptr", wc, "ushort") + ; Convert the source pBitmap into a hBitmap manually. + ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader + hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") + bi := Buffer(40, 0) ; sizeof(bi) = 40 + NumPut( "uint", 40, bi, 0) ; Size + NumPut( "int", w, bi, 4) ; Width + NumPut( "int", -h, bi, 8) ; Height - Negative so (0, 0) is top-left. + NumPut("ushort", 1, bi, 12) ; Planes + NumPut("ushort", 32, bi, 14) ; BitCount / BitsPerPixel + hbm := DllCall("CreateDIBSection", "ptr", hdc, "ptr", bi, "uint", 0, "ptr*", &pBits:=0, "ptr", 0, "uint", 0, "ptr") + obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") + + DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", pBitmap, "int*", &format:=0) + + ; Case 1: Image is not scaled. + if (s = 1) { + ; Transfer data from source pBitmap to an hBitmap manually. + Rect := Buffer(16, 0) ; sizeof(Rect) = 16 + NumPut( "uint", width, Rect, 8) ; Width + NumPut( "uint", height, Rect, 12) ; Height + BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + NumPut( "int", 4 * width, BitmapData, 8) ; Stride + NumPut( "ptr", pBits, BitmapData, 16) ; Scan0 + DllCall("gdiplus\GdipBitmapLockBits" + , "ptr", pBitmap + , "ptr", Rect + , "uint", 5 ; ImageLockMode.UserInputBuffer | ImageLockMode.ReadOnly + , "int", 0xE200B ; Format32bppPArgb + , "ptr", BitmapData) ; Contains the pointer (pBits) to the hbm. + DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", BitmapData) + } + + ; Case 2: Image is scaled. + else { + ; Create a graphics context from the device context. + DllCall("gdiplus\GdipCreateFromHDC", "ptr", hdc , "ptr*", &pGraphics:=0) + + ; Set settings in graphics context. + DllCall("gdiplus\GdipSetPixelOffsetMode", "ptr", pGraphics, "int", 2) ; Half pixel offset. + DllCall("gdiplus\GdipSetCompositingMode", "ptr", pGraphics, "int", 1) ; Overwrite/SourceCopy. + DllCall("gdiplus\GdipSetInterpolationMode", "ptr", pGraphics, "int", 7) ; HighQualityBicubic + + ; Draw Image. + DllCall("gdiplus\GdipCreateImageAttributes", "ptr*", &ImageAttr:=0) + DllCall("gdiplus\GdipSetImageAttributesWrapMode", "ptr", ImageAttr, "int", 3) ; WrapModeTileFlipXY + DllCall("gdiplus\GdipDrawImageRectRectI" + , "ptr", pGraphics + , "ptr", pBitmap + , "int", 0, "int", 0, "int", w, "int", h ; destination rectangle + , "int", 0, "int", 0, "int", width, "int", height ; source rectangle + , "int", 2 + , "ptr", ImageAttr + , "ptr", 0 + , "ptr", 0) + DllCall("gdiplus\GdipDisposeImageAttributes", "ptr", ImageAttr) + + ; Clean up the graphics context. + DllCall("gdiplus\GdipDeleteGraphics", "ptr", pGraphics) + } WS_VISIBLE := 0x10000000 WS_SYSMENU := 0x80000 @@ -1637,33 +1695,6 @@ class ImagePut { style := WS_CAPTION | WS_SYSMENU | WS_CLIPCHILDREN | WS_POPUP | WS_CLIPSIBLINGS ;| WS_SIZEBOX WS_VISIBLE | styleEx := WS_EX_TOPMOST | WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME ;| WS_EX_STATICEDGE - ; Get Bitmap width and height. - DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) - DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) - - ; If both dimensions exceed the screen boundaries, compare the aspect ratio of the image - ; to the aspect ratio of the screen to determine the scale factor. Default scale is 1. - s := (width > A_ScreenWidth) && (width / height > A_ScreenWidth / A_ScreenHeight) ? A_ScreenWidth / width - : (height > A_ScreenHeight) && (width / height <= A_ScreenWidth / A_ScreenHeight) ? A_ScreenHeight / height - : 1 - - w := IsObject(pos) && pos.has(3) ? pos[3] : s * width - h := IsObject(pos) && pos.has(4) ? pos[4] : s * height - - x := IsObject(pos) && pos.has(1) ? pos[1] : 0.5*(A_ScreenWidth - w) - y := IsObject(pos) && pos.has(2) ? pos[2] : 0.5*(A_ScreenHeight - h) - - ; Resolve dependent coordinates first, coordinates second, and distances last. - x2 := Round(x + w) - y2 := Round(y + h) - x := Round(x) - y := Round(y) - w := Round(w) - h := Round(h) -/* - if (s != 1) - this.BitmapScale(&pBitmap, s) -*/ rect := Buffer(16) NumPut("int", x, rect, 0) NumPut("int", y, rect, 4) @@ -1704,104 +1735,7 @@ class ImagePut { , "ptr", 0 ; lpParam , "ptr") - ; Convert the source pBitmap into a hBitmap manually. - ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader - hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") - bi := Buffer(40, 0) ; sizeof(bi) = 40 - NumPut( "uint", 40, bi, 0) ; Size - NumPut( "int", w, bi, 4) ; Width - NumPut( "int", -h, bi, 8) ; Height - Negative so (0, 0) is top-left. - NumPut("ushort", 1, bi, 12) ; Planes - NumPut("ushort", 32, bi, 14) ; BitCount / BitsPerPixel - hbm := DllCall("CreateDIBSection", "ptr", hdc, "ptr", bi, "uint", 0, "ptr*", &pBits:=0, "ptr", 0, "uint", 0, "ptr") - obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") - - DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", pBitmap, "int*", &format:=0) - -if (s = 1) { - ; Transfer data from source pBitmap to an hBitmap manually. - Rect := Buffer(16, 0) ; sizeof(Rect) = 16 - NumPut( "uint", width, Rect, 8) ; Width - NumPut( "uint", height, Rect, 12) ; Height - BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 - NumPut( "int", 4 * width, BitmapData, 8) ; Stride - NumPut( "ptr", pBits, BitmapData, 16) ; Scan0 - DllCall("gdiplus\GdipBitmapLockBits" - , "ptr", pBitmap - , "ptr", Rect - , "uint", 5 ; ImageLockMode.UserInputBuffer | ImageLockMode.ReadOnly - , "int", 0xE200B ; Format32bppPArgb - , "ptr", BitmapData) ; Contains the pointer (pBits) to the hbm. - DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", BitmapData) -} -else if ((0xFF00 & format) >> 8 = 24) { - - hdc2 := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") - hbm2 := this.put_hBitmap(pBitmap) - obm2 := DllCall("SelectObject", "ptr", hdc2, "ptr", hbm2, "ptr") - - ; Perform bilinear interpolation. See: https://stackoverflow.com/a/4358798 - DllCall("SetStretchBltMode", "ptr", hdc, "int", 4) ; HALFTONE - - ; Copies a portion of the screen to a new device context. - DllCall("gdi32\StretchBlt" - , "ptr", hdc, "int", 0, "int", 0, "int", w, "int", h - , "ptr", hdc2, "int", 0, "int", 0, "int", width, "int", height - , "uint", 0x00CC0020) ; SRCCOPY - - DllCall("SelectObject", "ptr", hdc2, "ptr", obm2) - DllCall("DeleteObject", "ptr", hbm2) - DllCall("DeleteDC", "ptr", hdc2) - - ; Unfortunately, using HALFTONE destroys the alpha channel. - ; There is no way around it, using SRCPAINT forces COLORONCOLOR (3). - ; See: https://devblogs.microsoft.com/oldnewthing/20210915-00/?p=105687 - - ; Create a single pixel to map onto a device context. - bi := Buffer(40, 0) ; sizeof(bi) = 40 - NumPut( "uint", 40, bi, 0) ; Size - NumPut( "int", 1, bi, 4) ; Width - NumPut( "int", 1, bi, 8) ; Height - NumPut("ushort", 1, bi, 12) ; Planes - NumPut("ushort", 32, bi, 14) ; BitCount / BitsPerPixel - - ; Restore alpha channel to opaque. - DllCall("gdi32\StretchDIBits" - , "ptr", hdc - , "int", 0, "int", 0, "int", w, "int", h - , "int", 0, "int", 0, "int", 1, "int", 1 - , "uint*", 0xFF000000 - , "ptr", bi - , "uint", 0 - , "uint", 0x00EE0086) ; SRCPAINT -} -else { - ; Create a graphics context from the device context. - DllCall("gdiplus\GdipCreateFromHDC", "ptr", hdc , "ptr*", &pGraphics:=0) - - ; Set settings in graphics context. - DllCall("gdiplus\GdipSetPixelOffsetMode", "ptr", pGraphics, "int", 2) ; Half pixel offset. - DllCall("gdiplus\GdipSetCompositingMode", "ptr", pGraphics, "int", 1) ; Overwrite/SourceCopy. - DllCall("gdiplus\GdipSetInterpolationMode", "ptr", pGraphics, "int", 7) ; HighQualityBicubic - - ; Draw Image. - DllCall("gdiplus\GdipCreateImageAttributes", "ptr*", &ImageAttr:=0) - DllCall("gdiplus\GdipSetImageAttributesWrapMode", "ptr", ImageAttr, "int", 3) ; WrapModeTileFlipXY - DllCall("gdiplus\GdipDrawImageRectRectI" - , "ptr", pGraphics - , "ptr", pBitmap - , "int", 0, "int", 0, "int", w, "int", h ; destination rectangle - , "int", 0, "int", 0, "int", width, "int", height ; source rectangle - , "int", 2 - , "ptr", ImageAttr - , "ptr", 0 - , "ptr", 0) - DllCall("gdiplus\GdipDisposeImageAttributes", "ptr", ImageAttr) - - ; Clean up the graphics context. - DllCall("gdiplus\GdipDeleteGraphics", "ptr", pGraphics) -} - + ; Draw the contents of the device context onto the layered window. DllCall("UpdateLayeredWindow" , "ptr", hwnd ; hWnd , "ptr", 0 ; hdcDst @@ -1820,6 +1754,31 @@ else { DllCall("DeleteDC", "ptr", hdc) return hwnd0 + + ; Define window behavior. + WindowProc(hwnd, uMsg, wParam, lParam) { + + ; WM_DESTROY + if (uMsg = 0x2) { + return Persistent(false) + } + + ; WM_LBUTTONDOWN + if (uMsg = 0x201) { + parent := DllCall("GetParent", "ptr", hwnd, "ptr") + hwnd := (parent != A_ScriptHwnd && parent != 0) ? parent : hwnd + return DllCall("DefWindowProc", "ptr", hwnd, "uint", 0xA1, "uptr", 2, "ptr", 0, "ptr") + } + + ; WM_RBUTTONUP + if (uMsg = 0x205) { + parent := DllCall("GetParent", "ptr", hwnd, "ptr") + hwnd := (parent != A_ScriptHwnd && parent != 0) ? parent : hwnd + return DllCall("DestroyWindow", "ptr", hwnd) + } + + return DllCall("DefWindowProc", "ptr", hwnd, "uint", uMsg, "uptr", wParam, "ptr", lParam, "ptr") + } } static put_desktop(pBitmap) { From fc450078e1eeca44e512d119cccdc05e38037af9 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 4 Jan 2022 19:00:36 -0500 Subject: [PATCH 135/492] Refactor put_window into separate parts --- ImagePut (for v1).ahk | 365 ++++++++++++++++++++++++++---------------- ImagePut.ahk | 235 +++++++++++++++------------ 2 files changed, 356 insertions(+), 244 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 28a1a2fc..3a31b0d8 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1553,53 +1553,220 @@ class ImagePut { return [x,y,w,h] } - WindowProc(uMsg, wParam, lParam) { - hwnd := this + put_window(pBitmap, title := "", pos := "") { + WS_CAPTION := 0xC00000 + WS_CLIPCHILDREN := 0x2000000 + WS_EX_DLGMODALFRAME := 0x1 + WS_EX_TOPMOST := 0x8 + WS_EX_WINDOWEDGE := 0x100 + WS_POPUP := 0x80000000 + WS_SYSMENU := 0x80000 + WS_CHILD := 0x40000000 + WS_EX_LAYERED := 0x80000 + WS_VISIBLE := 0x10000000 + WS_EX_TOOLWINDOW := 0x80 + + style := WS_CAPTION | WS_SYSMENU | WS_CLIPCHILDREN | WS_POPUP + styleEx := WS_EX_TOPMOST | WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME - ; WM_DESTROY - if (uMsg = 0x2) { - Hotkey % "^+F12", Off - } + ; Get Bitmap width and height. + DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) + DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) - ; WM_LBUTTONDOWN - if (uMsg = 0x201) { - parent := DllCall("GetParent", "ptr", hwnd, "ptr") - hwnd := (parent != A_ScriptHwnd && parent != 0) ? parent : hwnd - return DllCall("DefWindowProc", "ptr", hwnd, "uint", 0xA1, "uptr", 2, "ptr", 0, "ptr") - } + ; If both dimensions exceed the screen boundaries, compare the aspect ratio of the image + ; to the aspect ratio of the screen to determine the scale factor. Default scale is 1. + s := (width > A_ScreenWidth) && (width / height > A_ScreenWidth / A_ScreenHeight) ? A_ScreenWidth / width + : (height > A_ScreenHeight) && (width / height <= A_ScreenWidth / A_ScreenHeight) ? A_ScreenHeight / height + : 1 + + w := IsObject(pos) && pos.HasKey(3) ? pos[3] : s * width + h := IsObject(pos) && pos.HasKey(4) ? pos[4] : s * height + + x := IsObject(pos) && pos.HasKey(1) ? pos[1] : 0.5*(A_ScreenWidth - w) + y := IsObject(pos) && pos.HasKey(2) ? pos[2] : 0.5*(A_ScreenHeight - h) + + ; Resolve dependent coordinates first, coordinates second, and distances last. + x2 := Round(x + w) + y2 := Round(y + h) + x := Round(x) + y := Round(y) + w := x2 - x + h := y2 - y + + VarSetCapacity(rect, 16) + NumPut( x, rect, 0, "int") + NumPut( y, rect, 4, "int") + NumPut(x2, rect, 8, "int") + NumPut(y2, rect, 12, "int") + + DllCall("AdjustWindowRectEx", "ptr", &rect, "uint", style, "uint", 0, "uint", styleEx) + + hwnd := DllCall("CreateWindowEx" + , "uint", styleEx + , "str", this.WindowClass() ; lpClassName + , "str", title ; lpWindowName + , "uint", style + , "int", NumGet(rect, 0, "int") + , "int", NumGet(rect, 4, "int") + , "int", NumGet(rect, 8, "int") - NumGet(rect, 0, "int") + , "int", NumGet(rect, 12, "int") - NumGet(rect, 4, "int") + , "ptr", A_ScriptHwnd ; hWndParent + , "ptr", 0 ; hMenu + , "ptr", 0 ; hInstance + , "ptr", 0 ; lpParam + , "ptr") + + ; Tests have shown that changing the system default colors has no effect on F0F0F0. + WinSet TransColor, % "F0F0F0", % "ahk_id" hwnd0 + + this.show(pBitmap, title, [0, 0, w, h], WS_CHILD | WS_VISIBLE, WS_EX_LAYERED, hwnd) + + DllCall("ShowWindow", "ptr", hwnd, "int", 1) + + return hwnd + } + + show(pBitmap, title := "", pos := "", style := 0x10000000, styleEx := 0x80088, parent := 0) { + ; Prevent the script from exiting early. + void := ObjBindMethod({}, {}) + Hotkey % "^+F12", % void, On - ; WM_RBUTTONUP - if (uMsg = 0x205) { - parent := DllCall("GetParent", "ptr", hwnd, "ptr") - hwnd := (parent != A_ScriptHwnd && parent != 0) ? parent : hwnd - return DllCall("DestroyWindow", "ptr", hwnd) - } + ; Get Bitmap width and height. + DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) + DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) - return DllCall("DefWindowProc", "ptr", hwnd, "uint", uMsg, "uptr", wParam, "ptr", lParam, "ptr") + ; If both dimensions exceed the screen boundaries, compare the aspect ratio of the image + ; to the aspect ratio of the screen to determine the scale factor. Default scale is 1. + s := (width > A_ScreenWidth) && (width / height > A_ScreenWidth / A_ScreenHeight) ? A_ScreenWidth / width + : (height > A_ScreenHeight) && (width / height <= A_ScreenWidth / A_ScreenHeight) ? A_ScreenHeight / height + : 1 + + w := IsObject(pos) && pos.HasKey(3) ? pos[3] : s * width + h := IsObject(pos) && pos.HasKey(4) ? pos[4] : s * height + + x := IsObject(pos) && pos.HasKey(1) ? pos[1] : 0.5*(A_ScreenWidth - w) + y := IsObject(pos) && pos.HasKey(2) ? pos[2] : 0.5*(A_ScreenHeight - h) + + ; Resolve dependent coordinates first, coordinates second, and distances last. + x2 := Round(x + w) + y2 := Round(y + h) + x := Round(x) + y := Round(y) + w := x2 - x + h := y2 - y + + ; Convert the source pBitmap into a hBitmap manually. + ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader + hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") + VarSetCapacity(bi, 40, 0) ; sizeof(bi) = 40 + NumPut( 40, bi, 0, "uint") ; Size + NumPut( width, bi, 4, "uint") ; Width + NumPut( -height, bi, 8, "int") ; Height - Negative so (0, 0) is top-left. + NumPut( 1, bi, 12, "ushort") ; Planes + NumPut( 32, bi, 14, "ushort") ; BitCount / BitsPerPixel + hbm := DllCall("CreateDIBSection", "ptr", hdc, "ptr", &bi, "uint", 0, "ptr*", pBits:=0, "ptr", 0, "uint", 0, "ptr") + obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") + + DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", pBitmap, "int*", format:=0) + + ; Case 1: Image is not scaled. + if (s = 1) { + ; Transfer data from source pBitmap to an hBitmap manually. + VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 + NumPut( width, Rect, 8, "uint") ; Width + NumPut( height, Rect, 12, "uint") ; Height + VarSetCapacity(BitmapData, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + NumPut( 4 * width, BitmapData, 8, "int") ; Stride + NumPut( pBits, BitmapData, 16, "ptr") ; Scan0 + DllCall("gdiplus\GdipBitmapLockBits" + , "ptr", pBitmap + , "ptr", &Rect + , "uint", 5 ; ImageLockMode.UserInputBuffer | ImageLockMode.ReadOnly + , "int", 0xE200B ; Format32bppPArgb + , "ptr", &BitmapData) ; Contains the pointer (pBits) to the hbm. + DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", &BitmapData) } - put_window(pBitmap, title := "") { - ; Make it permanent. - void := ObjBindMethod({}, {}) - Hotkey % "^+F12", % void, On + ; Case 2: Image is scaled. + else { + ; Create a graphics context from the device context. + DllCall("gdiplus\GdipCreateFromHDC", "ptr", hdc , "ptr*", &pGraphics:=0) + + ; Set settings in graphics context. + DllCall("gdiplus\GdipSetPixelOffsetMode", "ptr", pGraphics, "int", 2) ; Half pixel offset. + DllCall("gdiplus\GdipSetCompositingMode", "ptr", pGraphics, "int", 1) ; Overwrite/SourceCopy. + DllCall("gdiplus\GdipSetInterpolationMode", "ptr", pGraphics, "int", 7) ; HighQualityBicubic + + ; Draw Image. + DllCall("gdiplus\GdipCreateImageAttributes", "ptr*", ImageAttr:=0) + DllCall("gdiplus\GdipSetImageAttributesWrapMode", "ptr", ImageAttr, "int", 3) ; WrapModeTileFlipXY + DllCall("gdiplus\GdipDrawImageRectRectI" + , "ptr", pGraphics + , "ptr", pBitmap + , "int", 0, "int", 0, "int", w, "int", h ; destination rectangle + , "int", 0, "int", 0, "int", width, "int", height ; source rectangle + , "int", 2 + , "ptr", ImageAttr + , "ptr", 0 + , "ptr", 0) + DllCall("gdiplus\GdipDisposeImageAttributes", "ptr", ImageAttr) + + ; Clean up the graphics context. + DllCall("gdiplus\GdipDeleteGraphics", "ptr", pGraphics) + } + + hwnd := DllCall("CreateWindowEx" + , "uint", styleEx | 0x80000 ; dwExStyle + , "str", this.WindowClass() ; lpClassName + , "str", title ; lpWindowName + , "uint", style ; dwStyle + , "int", x + , "int", y + , "int", w + , "int", h + , "ptr", parent ? parent : 0 ; hWndParent + , "ptr", 0 ; hMenu + , "ptr", 0 ; hInstance + , "ptr", 0 ; lpParam + , "ptr") + + ; Draw the contents of the device context onto the layered window. + DllCall("UpdateLayeredWindow" + , "ptr", hwnd ; hWnd + , "ptr", 0 ; hdcDst + , "ptr", 0 ; *pptDst + ,"uint64*", w | h << 32 ; *psize + , "ptr", hdc ; hdcSrc + , "int64*", 0 ; *pptSrc + , "uint", 0 ; crKey + , "uint*", 0xFF << 16 | 0x01 << 24 ; *pblend + , "uint", 2) ; dwFlags + + ; Cleanup the hBitmap and device contexts. + DllCall("SelectObject", "ptr", hdc, "ptr", obm) + DllCall("DeleteObject", "ptr", hbm) + DllCall("DeleteDC", "ptr", hdc) + + return hwnd0 + } + WindowClass() { + ; The class name is ImagePut. cls := this.__class - pWndProc := RegisterCallback(this.WindowProc, "Fast",, &this) + VarSetCapacity(wc, size := _ ? 48:80) ; sizeof(WNDCLASSEX) = 48, 80 + + ; Check if the window class is already registered. + if DllCall("GetClassInfoEx", "ptr", 0, "str", cls, "ptr", wc) + return cls + ; Create window data. + pWndProc := RegisterCallback(this.WindowProc,,, &this) hCursor := DllCall("LoadCursor", "ptr", 0, "ptr", 32512, "ptr") ; IDC_ARROW - ;hBrush := DllCall("CreateSolidBrush", "uint", 0x00F0F0F0, "ptr") hBrush := DllCall("GetStockObject", "int", 5, "ptr") ; Hollow_brush - ; explanation or guess: There's 2 layers. The bottom layer is F0F0F0 and it is set to transparent. - ; However, transparency is click through. But if the hollow brush is used instead, it paints with - ; no color. But the system interprets that as the default color, F0F0F0. So later when F0F0F0 is made - ; transparent, it can't set the bounds as click though, because the system used the default color to - ; represent the empty color, and all we did was remove the system shading. (Just a guess.) - ; struct tagWNDCLASSEXA - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexa ; struct tagWNDCLASSEXW - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexw _ := (A_PtrSize = 4) - VarSetCapacity(wc, size := _ ? 48:80) ; sizeof(WNDCLASSEX) = 48, 80 NumPut( size, wc, 0, "uint") ; cbSize NumPut( 0, wc, 4, "uint") ; style NumPut( pWndProc, wc, 8, "ptr") ; lpfnWndProc @@ -1616,120 +1783,34 @@ class ImagePut { ; Registers a window class for subsequent use in calls to the CreateWindow or CreateWindowEx function. DllCall("RegisterClassEx", "ptr", &wc, "ushort") - WS_VISIBLE := 0x10000000 - WS_SYSMENU := 0x80000 - WS_CHILD := 0x40000000 - WS_EX_TOPMOST := 0x8 - WS_EX_LAYERED := 0x80000 - WS_TILEDWINDOW := 0xCF0000 - WS_CAPTION := 0xC00000 - WS_EX_STATICEDGE := 0x20000 - WS_EX_WINDOWEDGE := 0x100 - WS_SIZEBOX := 0x40000 - WS_CLIPCHILDREN := 0x2000000 - WS_POPUP := 0x80000000 - WS_BORDER := 0x800000 - WS_EX_TOOLWINDOW := 0x80 - WS_CLIPSIBLINGS := 0x4000000 - WS_EX_TRANSPARENT := 0x20 - WS_EX_DLGMODALFRAME := 0x1 - - style := WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_CLIPCHILDREN | WS_POPUP | WS_CLIPSIBLINGS ;| WS_SIZEBOX - styleEx := WS_EX_TOPMOST | WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME ;| WS_EX_STATICEDGE + ; Return the class name as a string. + return cls + } + ; Define window behavior. + WindowProc(uMsg, wParam, lParam) { + hwnd := this + ; WM_DESTROY + if (uMsg = 0x2) { + Hotkey % "^+F12", Off + } - ; Get Bitmap width and height. - DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) - DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) + ; WM_LBUTTONDOWN + if (uMsg = 0x201) { + parent := DllCall("GetParent", "ptr", hwnd, "ptr") + hwnd := (parent != A_ScriptHwnd && parent != 0) ? parent : hwnd + return DllCall("DefWindowProc", "ptr", hwnd, "uint", 0xA1, "uptr", 2, "ptr", 0, "ptr") + } - balance := width / height > A_ScreenWidth / A_ScreenHeight - if (balance && width > A_ScreenWidth) - scale := (A_ScreenWidth / width), width := A_ScreenWidth, height *= scale - if (!balance && height > A_ScreenHeight) - scale := (A_ScreenHeight / height), height := A_ScreenHeight, width *= scale - if (scale != "") - this.BitmapScale(pBitmap, scale) - - VarSetCapacity(rect, 16) - NumPut(Floor((A_ScreenWidth - width) / 2.0), rect, 0, "int") - NumPut(Floor((A_ScreenHeight - height) / 2.0), rect, 4, "int") - NumPut(Floor((A_ScreenWidth + width) / 2.0), rect, 8, "int") - NumPut(Floor((A_ScreenHeight + height) / 2.0), rect, 12, "int") - - DllCall("AdjustWindowRectEx", "ptr", &rect, "uint", style, "uint", 0, "uint", styleEx) - , x := NumGet(rect, 0, "int") - , y := NumGet(rect, 4, "int") - , w := NumGet(rect, 8, "int") - NumGet(rect, 0, "int") - , h := NumGet(rect, 12, "int") - NumGet(rect, 4, "int") - - hwnd0 := DllCall("CreateWindowEx" - , "uint", styleEx - , "str", "ImagePut" ; lpClassName - , "str", title ;"Pichu" ; lpWindowName - , "uint", style - , "int", x ; X - , "int", y ; Y - , "int", w ; nWidth - , "int", h ; nHeight - , "ptr", A_ScriptHwnd ; hWndParent - , "ptr", 0 ; hMenu - , "ptr", 0 ; hInstance - , "ptr", 0 ; lpParam - , "ptr") - - ;if transparent - WinSet TransColor, % "F0F0F0", % "ahk_id" hwnd0 - - vWinStyle := WS_VISIBLE | WS_CHILD - vWinExStyle := WS_EX_LAYERED ;| WS_EX_TOPMOST - - hwnd := DllCall("CreateWindowEx" - , "uint", vWinExStyle ; dwExStyle - , "str", "ImagePut" ; lpClassName - , "str", "Pikachu" ; lpWindowName - , "uint", vWinStyle ; dwStyle - , "int", 0 ; X - , "int", 0 ; Y - , "int", width ; nWidth - , "int", height ; nHeight - , "ptr", hwnd0 ; hWndParent - , "ptr", 0 ; hMenu - , "ptr", 0 ; hInstance - , "ptr", 0 ; lpParam - , "ptr") - - ;DllCall("ShowWindow", "ptr", hwnd, "int", 1) - - hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") - hbm := this.put_hBitmap(pBitmap) - obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") - ;DllCall("gdiplus\GdipCreateFromHDC", "ptr", hdc , "ptr*", gfx:=0) - - DllCall("UpdateLayeredWindow" - , "ptr", hwnd ; hWnd - , "ptr", 0 ; hdcDst - ,"uint64*", 0 | 0 << 32 ; *pptDst - ,"uint64*", width | height << 32 ; *psize - , "ptr", hdc ; hdcSrc - , "int64*", 0 ; *pptSrc - , "uint", 0 ; crKey - , "uint*", 0xFF << 16 | 0x01 << 24 ; *pblend - , "uint", 2) ; dwFlags - - - - ;MsgBox Format("{:X}", Style) " | " Format("{:X}", WinGetStyle(hwnd0)) - ;MsgBox Format("{:X}", StyleEx) " | " Format("{:X}", WinGetExStyle(hwnd0)) - - ;MsgBox Format("{:X}", vWinStyle) " | " Format("{:X}", WinGetStyle(hwnd)) - ;MsgBox Format("{:X}", vWinExStyle) " | " Format("{:X}", WinGetExStyle(hwnd)) + ; WM_RBUTTONUP + if (uMsg = 0x205) { + parent := DllCall("GetParent", "ptr", hwnd, "ptr") + hwnd := (parent != A_ScriptHwnd && parent != 0) ? parent : hwnd + return DllCall("DestroyWindow", "ptr", hwnd) + } - ; Cleanup the hBitmap and device contexts. - DllCall("SelectObject", "ptr", hdc, "ptr", obm) - DllCall("DeleteObject", "ptr", hbm) - DllCall("DeleteDC", "ptr", hdc) + return DllCall("DefWindowProc", "ptr", hwnd, "uint", uMsg, "uptr", wParam, "ptr", lParam, "ptr") + } - return hwnd0 - } put_desktop(pBitmap) { ; Thanks Gerald Degeneve - https://www.codeproject.com/Articles/856020/Draw-Behind-Desktop-Icons-in-Windows-plus diff --git a/ImagePut.ahk b/ImagePut.ahk index 0ade7615..0e22c0cc 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1554,41 +1554,82 @@ class ImagePut { } static put_window(pBitmap, title := "", pos := "") { + WS_CAPTION := 0xC00000 + WS_CLIPCHILDREN := 0x2000000 + WS_EX_DLGMODALFRAME := 0x1 + WS_EX_TOPMOST := 0x8 + WS_EX_WINDOWEDGE := 0x100 + WS_POPUP := 0x80000000 + WS_SYSMENU := 0x80000 + WS_CHILD := 0x40000000 + WS_EX_LAYERED := 0x80000 + WS_VISIBLE := 0x10000000 + WS_EX_TOOLWINDOW := 0x80 + + style := WS_CAPTION | WS_SYSMENU | WS_CLIPCHILDREN | WS_POPUP + styleEx := WS_EX_TOPMOST | WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME - ; Prevent the script from exiting early. - Persistent(true) + ; Get Bitmap width and height. + DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) + DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) - ; The class name is ImagePut. - cls := this.prototype.__class - wc := Buffer(A_PtrSize = 4 ? 48:80) ; sizeof(WNDCLASSEX) = 48, 80 + ; If both dimensions exceed the screen boundaries, compare the aspect ratio of the image + ; to the aspect ratio of the screen to determine the scale factor. Default scale is 1. + s := (width > A_ScreenWidth) && (width / height > A_ScreenWidth / A_ScreenHeight) ? A_ScreenWidth / width + : (height > A_ScreenHeight) && (width / height <= A_ScreenWidth / A_ScreenHeight) ? A_ScreenHeight / height + : 1 - ; Register the window class. - if !DllCall("GetClassInfoEx", "ptr", 0, "str", cls, "ptr", wc) { - - ; Create window data. - pWndProc := CallbackCreate(WindowProc) - hCursor := DllCall("LoadCursor", "ptr", 0, "ptr", 32512, "ptr") ; IDC_ARROW - hBrush := DllCall("GetStockObject", "int", 5, "ptr") ; Hollow_brush - - ; struct tagWNDCLASSEXA - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexa - ; struct tagWNDCLASSEXW - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexw - _ := (A_PtrSize = 4) - NumPut( "uint", wc.size, wc, 0) ; cbSize - NumPut( "uint", 0, wc, 4) ; style - NumPut( "ptr", pWndProc, wc, 8) ; lpfnWndProc - NumPut( "int", 0, wc, _ ? 12:16) ; cbClsExtra - NumPut( "int", 0, wc, _ ? 16:20) ; cbWndExtra - NumPut( "ptr", 0, wc, _ ? 20:24) ; hInstance - NumPut( "ptr", 0, wc, _ ? 24:32) ; hIcon - NumPut( "ptr", hCursor, wc, _ ? 28:40) ; hCursor - NumPut( "ptr", hBrush, wc, _ ? 32:48) ; hbrBackground - NumPut( "ptr", 0, wc, _ ? 36:56) ; lpszMenuName - NumPut( "ptr", StrPtr(cls), wc, _ ? 40:64) ; lpszClassName - NumPut( "ptr", 0, wc, _ ? 44:72) ; hIconSm - - ; Registers a window class for subsequent use in calls to the CreateWindow or CreateWindowEx function. - DllCall("RegisterClassEx", "ptr", wc, "ushort") - } + w := IsObject(pos) && pos.has(3) ? pos[3] : s * width + h := IsObject(pos) && pos.has(4) ? pos[4] : s * height + + x := IsObject(pos) && pos.has(1) ? pos[1] : 0.5*(A_ScreenWidth - w) + y := IsObject(pos) && pos.has(2) ? pos[2] : 0.5*(A_ScreenHeight - h) + + ; Resolve dependent coordinates first, coordinates second, and distances last. + x2 := Round(x + w) + y2 := Round(y + h) + x := Round(x) + y := Round(y) + w := x2 - x + h := y2 - y + + rect := Buffer(16) + NumPut("int", x, rect, 0) + NumPut("int", y, rect, 4) + NumPut("int", x2, rect, 8) + NumPut("int", y2, rect, 12) + + DllCall("AdjustWindowRectEx", "ptr", rect, "uint", style, "uint", 0, "uint", styleEx) + + hwnd := DllCall("CreateWindowEx" + , "uint", styleEx + , "str", this.WindowClass() ; lpClassName + , "str", title ; lpWindowName + , "uint", style + , "int", NumGet(rect, 0, "int") + , "int", NumGet(rect, 4, "int") + , "int", NumGet(rect, 8, "int") - NumGet(rect, 0, "int") + , "int", NumGet(rect, 12, "int") - NumGet(rect, 4, "int") + , "ptr", A_ScriptHwnd ; hWndParent + , "ptr", 0 ; hMenu + , "ptr", 0 ; hInstance + , "ptr", 0 ; lpParam + , "ptr") + + ; Tests have shown that changing the system default colors has no effect on F0F0F0. + WinSetTransColor "F0F0F0", hwnd + + this.show(pBitmap, title, [0, 0, w, h], WS_CHILD | WS_VISIBLE, WS_EX_LAYERED, hwnd) + + DllCall("ShowWindow", "ptr", hwnd, "int", 1) + + return hwnd + } + + static show(pBitmap, title := "", pos := "", style := 0x10000000, styleEx := 0x80088, parent := 0) { + + ; Prevent the script from exiting early. + Persistent(true) ; Get Bitmap width and height. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) @@ -1674,86 +1715,76 @@ class ImagePut { DllCall("gdiplus\GdipDeleteGraphics", "ptr", pGraphics) } - WS_VISIBLE := 0x10000000 - WS_SYSMENU := 0x80000 - WS_CHILD := 0x40000000 - WS_EX_TOPMOST := 0x8 - WS_EX_LAYERED := 0x80000 - WS_TILEDWINDOW := 0xCF0000 - WS_CAPTION := 0xC00000 - WS_EX_STATICEDGE := 0x20000 - WS_EX_WINDOWEDGE := 0x100 - WS_SIZEBOX := 0x40000 - WS_CLIPCHILDREN := 0x2000000 - WS_POPUP := 0x80000000 - WS_BORDER := 0x800000 - WS_EX_TOOLWINDOW := 0x80 - WS_CLIPSIBLINGS := 0x4000000 - WS_EX_TRANSPARENT := 0x20 - WS_EX_DLGMODALFRAME := 0x1 - - style := WS_CAPTION | WS_SYSMENU | WS_CLIPCHILDREN | WS_POPUP | WS_CLIPSIBLINGS ;| WS_SIZEBOX WS_VISIBLE | - styleEx := WS_EX_TOPMOST | WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME ;| WS_EX_STATICEDGE - - rect := Buffer(16) - NumPut("int", x, rect, 0) - NumPut("int", y, rect, 4) - NumPut("int", x2, rect, 8) - NumPut("int", y2, rect, 12) - - DllCall("AdjustWindowRectEx", "ptr", rect, "uint", style, "uint", 0, "uint", styleEx) - - hwnd0 := DllCall("CreateWindowEx" - , "uint", styleEx - , "str", "ImagePut" ; lpClassName - , "str", title ; lpWindowName - , "uint", style - , "int", NumGet(rect, 0, "int") - , "int", NumGet(rect, 4, "int") - , "int", NumGet(rect, 8, "int") - NumGet(rect, 0, "int") - , "int", NumGet(rect, 12, "int") - NumGet(rect, 4, "int") - , "ptr", A_ScriptHwnd ; hWndParent - , "ptr", 0 ; hMenu - , "ptr", 0 ; hInstance - , "ptr", 0 ; lpParam - , "ptr") - - WinSetTransColor "F0F0F0", hwnd0 - hwnd := DllCall("CreateWindowEx" - , "uint", WS_EX_LAYERED ; dwExStyle - , "str", cls ; lpClassName - , "str", "Pikachu" ; lpWindowName - , "uint", WS_VISIBLE | WS_CHILD ; dwStyle - , "int", 0 - , "int", 0 - , "int", w - , "int", h - , "ptr", hwnd0 ; hWndParent - , "ptr", 0 ; hMenu - , "ptr", 0 ; hInstance - , "ptr", 0 ; lpParam - , "ptr") + , "uint", styleEx | 0x80000 ; dwExStyle + , "str", this.WindowClass() ; lpClassName + , "str", title ; lpWindowName + , "uint", style ; dwStyle + , "int", x + , "int", y + , "int", w + , "int", h + , "ptr", parent ? parent : 0 ; hWndParent + , "ptr", 0 ; hMenu + , "ptr", 0 ; hInstance + , "ptr", 0 ; lpParam + , "ptr") ; Draw the contents of the device context onto the layered window. DllCall("UpdateLayeredWindow" - , "ptr", hwnd ; hWnd - , "ptr", 0 ; hdcDst - ,"uint64*", 0 | 0 << 32 ; *pptDst - ,"uint64*", w | h << 32 ; *psize - , "ptr", hdc ; hdcSrc - , "int64*", 0 ; *pptSrc - , "uint", 0 ; crKey - , "uint*", 0xFF << 16 | 0x01 << 24 ; *pblend - , "uint", 2) ; dwFlags - DllCall("ShowWindow", "ptr", hwnd0, "int", 1) + , "ptr", hwnd ; hWnd + , "ptr", 0 ; hdcDst + , "ptr", 0 ; *pptDst + ,"uint64*", w | h << 32 ; *psize + , "ptr", hdc ; hdcSrc + , "int64*", 0 ; *pptSrc + , "uint", 0 ; crKey + , "uint*", 0xFF << 16 | 0x01 << 24 ; *pblend + , "uint", 2) ; dwFlags ; Cleanup the hBitmap and device contexts. DllCall("SelectObject", "ptr", hdc, "ptr", obm) DllCall("DeleteObject", "ptr", hbm) DllCall("DeleteDC", "ptr", hdc) - return hwnd0 + return hwnd + } + + static WindowClass() { + ; The class name is ImagePut. + cls := this.prototype.__class + wc := Buffer(A_PtrSize = 4 ? 48:80) ; sizeof(WNDCLASSEX) = 48, 80 + + ; Check if the window class is already registered. + if DllCall("GetClassInfoEx", "ptr", 0, "str", cls, "ptr", wc) + return cls + + ; Create window data. + pWndProc := CallbackCreate(WindowProc) + hCursor := DllCall("LoadCursor", "ptr", 0, "ptr", 32512, "ptr") ; IDC_ARROW + hBrush := DllCall("GetStockObject", "int", 5, "ptr") ; Hollow_brush + + ; struct tagWNDCLASSEXA - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexa + ; struct tagWNDCLASSEXW - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexw + _ := (A_PtrSize = 4) + NumPut( "uint", wc.size, wc, 0) ; cbSize + NumPut( "uint", 0, wc, 4) ; style + NumPut( "ptr", pWndProc, wc, 8) ; lpfnWndProc + NumPut( "int", 0, wc, _ ? 12:16) ; cbClsExtra + NumPut( "int", 0, wc, _ ? 16:20) ; cbWndExtra + NumPut( "ptr", 0, wc, _ ? 20:24) ; hInstance + NumPut( "ptr", 0, wc, _ ? 24:32) ; hIcon + NumPut( "ptr", hCursor, wc, _ ? 28:40) ; hCursor + NumPut( "ptr", hBrush, wc, _ ? 32:48) ; hbrBackground + NumPut( "ptr", 0, wc, _ ? 36:56) ; lpszMenuName + NumPut( "ptr", StrPtr(cls), wc, _ ? 40:64) ; lpszClassName + NumPut( "ptr", 0, wc, _ ? 44:72) ; hIconSm + + ; Registers a window class for subsequent use in calls to the CreateWindow or CreateWindowEx function. + DllCall("RegisterClassEx", "ptr", wc, "ushort") + + ; Return the class name as a string. + return cls ; Define window behavior. WindowProc(hwnd, uMsg, wParam, lParam) { From dcd7cb50e2e3215bfd9c28b509027612566b215b Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 4 Jan 2022 19:28:23 -0500 Subject: [PATCH 136/492] Add ImageShow() --- ImagePut (for v1).ahk | 27 ++++++++++++++++++--------- ImagePut.ahk | 43 ++++++++++++++++++++++++++----------------- 2 files changed, 44 insertions(+), 26 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 3a31b0d8..0c664998 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -99,15 +99,20 @@ ImagePutWallpaper(image) { } ; Puts the image in a window and returns a handle to a window. -; title - Window Caption Title | string -> MyTitle -ImagePutWindow(image, title := "") { - return ImagePut("window", image, title) +; title - Window Title | string -> MyTitle +; pos - Window Coordinates | array -> [x,y,w,h] or [0,0] +ImagePutWindow(image, title := "", pos := "") { + return ImagePut("window", image, title, pos) } - -ImageShow() { - return +; title - Window Title | string -> MyTitle +; pos - Window Coordinates | array -> [x,y,w,h] or [0,0] +; style - Window Style | uint -> WS_VISIBLE +; styleEx - Window Extended Style | uint -> WS_EX_LAYERED +; parent - Window Parent | ptr -> hwnd +ImageShow(image, title := "", pos := "", style := 0x10000000, styleEx := 0x80088, parent := 0) { + return ImagePut("show", image, title, pos, style, styleEx, parent) } ImagePut(cotype, image, p*) { @@ -513,7 +518,7 @@ class ImagePut { throw Exception("Conversion from " type " to bitmap is not supported.") } - BitmapToCoimage(cotype, pBitmap, p1 := "", p2 := "", p*) { + BitmapToCoimage(cotype, pBitmap, p1:="", p2:="", p3:="", p4:="", p5:="", p*) { ; BitmapToCoimage("clipboard", pBitmap) if (cotype = "clipboard") return this.put_clipboard(pBitmap) @@ -526,9 +531,13 @@ class ImagePut { if (cotype = "screenshot") return this.put_screenshot(pBitmap, p1, p2) - ; BitmapToCoimage("window", pBitmap, title) + ; BitmapToCoimage("show", pBitmap, title, pos, style, styleEx, parent) + if (cotype = "show") + return this.show(pBitmap, p1, p2, p3, p4, p5) + + ; BitmapToCoimage("window", pBitmap, title, pos) if (cotype = "window") - return this.put_window(pBitmap, p1) + return this.put_window(pBitmap, p1, p2) ; BitmapToCoimage("desktop", pBitmap) if (cotype = "desktop") diff --git a/ImagePut.ahk b/ImagePut.ahk index 0e22c0cc..4579a539 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -99,15 +99,20 @@ ImagePutWallpaper(image) { } ; Puts the image in a window and returns a handle to a window. -; title - Window Caption Title | string -> MyTitle -ImagePutWindow(image, title := "") { - return ImagePut("window", image, title) +; title - Window Title | string -> MyTitle +; pos - Window Coordinates | array -> [x,y,w,h] or [0,0] +ImagePutWindow(image, title := "", pos := "") { + return ImagePut("window", image, title, pos) } - -ImageShow() { - return +; title - Window Title | string -> MyTitle +; pos - Window Coordinates | array -> [x,y,w,h] or [0,0] +; style - Window Style | uint -> WS_VISIBLE +; styleEx - Window Extended Style | uint -> WS_EX_LAYERED +; parent - Window Parent | ptr -> hwnd +ImageShow(image, title := "", pos := "", style := 0x10000000, styleEx := 0x80088, parent := 0) { + return ImagePut("show", image, title, pos, style, styleEx, parent) } /* ImagePut(cotype, image, p*) { @@ -513,7 +518,7 @@ class ImagePut { throw Error("Conversion from " type " to bitmap is not supported.") } - static BitmapToCoimage(cotype, pBitmap, p1 := "", p2 := "", p*) { + static BitmapToCoimage(cotype, pBitmap, p1:="", p2:="", p3:="", p4:="", p5:="", p*) { ; BitmapToCoimage("clipboard", pBitmap) if (cotype = "clipboard") return this.put_clipboard(pBitmap) @@ -526,9 +531,13 @@ class ImagePut { if (cotype = "screenshot") return this.put_screenshot(pBitmap, p1, p2) - ; BitmapToCoimage("window", pBitmap, title) + ; BitmapToCoimage("show", pBitmap, title, pos, style, styleEx, parent) + if (cotype = "show") + return this.show(pBitmap, p1, p2, p3, p4, p5) + + ; BitmapToCoimage("window", pBitmap, title, pos) if (cotype = "window") - return this.put_window(pBitmap, p1) + return this.put_window(pBitmap, p1, p2) ; BitmapToCoimage("desktop", pBitmap) if (cotype = "desktop") @@ -1579,11 +1588,11 @@ class ImagePut { : (height > A_ScreenHeight) && (width / height <= A_ScreenWidth / A_ScreenHeight) ? A_ScreenHeight / height : 1 - w := IsObject(pos) && pos.has(3) ? pos[3] : s * width - h := IsObject(pos) && pos.has(4) ? pos[4] : s * height + w := IsObject(pos) && pos.Has(3) ? pos[3] : s * width + h := IsObject(pos) && pos.Has(4) ? pos[4] : s * height - x := IsObject(pos) && pos.has(1) ? pos[1] : 0.5*(A_ScreenWidth - w) - y := IsObject(pos) && pos.has(2) ? pos[2] : 0.5*(A_ScreenHeight - h) + x := IsObject(pos) && pos.Has(1) ? pos[1] : 0.5*(A_ScreenWidth - w) + y := IsObject(pos) && pos.Has(2) ? pos[2] : 0.5*(A_ScreenHeight - h) ; Resolve dependent coordinates first, coordinates second, and distances last. x2 := Round(x + w) @@ -1641,11 +1650,11 @@ class ImagePut { : (height > A_ScreenHeight) && (width / height <= A_ScreenWidth / A_ScreenHeight) ? A_ScreenHeight / height : 1 - w := IsObject(pos) && pos.has(3) ? pos[3] : s * width - h := IsObject(pos) && pos.has(4) ? pos[4] : s * height + w := IsObject(pos) && pos.Has(3) ? pos[3] : s * width + h := IsObject(pos) && pos.Has(4) ? pos[4] : s * height - x := IsObject(pos) && pos.has(1) ? pos[1] : 0.5*(A_ScreenWidth - w) - y := IsObject(pos) && pos.has(2) ? pos[2] : 0.5*(A_ScreenHeight - h) + x := IsObject(pos) && pos.Has(1) ? pos[1] : 0.5*(A_ScreenWidth - w) + y := IsObject(pos) && pos.Has(2) ? pos[2] : 0.5*(A_ScreenHeight - h) ; Resolve dependent coordinates first, coordinates second, and distances last. x2 := Round(x + w) From 9d67dd9a7366458df172b922a720a6f198ba8b74 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 5 Jan 2022 23:54:49 -0500 Subject: [PATCH 137/492] Use BitmapBuffer class over prototype object --- ImagePut (for v1).ahk | 17 ++++++++++++----- ImagePut.ahk | 17 ++++++++++++----- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 0c664998..83e7c2d6 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1517,11 +1517,18 @@ class ImagePut { } put_buffer(pBitmap) { - buffer := {__New: ObjBindMethod(this, "gdiplusStartup") ; Increment GDI+ reference count - , __Delete: ObjBindMethod(this, "gdiplusShutdown", "smart_pointer", pBitmap)} - buffer := new buffer ; On deletion the buffer object will dispose of the bitmap. - buffer.pBitmap := pBitmap ; And it will decrement this.gdiplus. - return buffer + return new ImagePut.BitmapBuffer(pBitmap) + } + + class BitmapBuffer { + __New(pBitmap) { + this.pBitmap := pBitmap + ImagePut.gdiplusStartup() + } + + __Delete() { + ImagePut.gdiplusShutdown("smart_pointer", this.pBitmap) + } } put_screenshot(pBitmap, screenshot := "", alpha := "") { diff --git a/ImagePut.ahk b/ImagePut.ahk index 4579a539..6aec25e5 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1517,11 +1517,18 @@ class ImagePut { } static put_buffer(pBitmap) { - buffer := {pBitmap: pBitmap} - .DefineMethod("__New" , (self) => (this.gdiplusStartup(), self)) ; Increment GDI+ reference count - .DefineMethod("__Delete", (self) => (this.gdiplusShutdown("smart_pointer", self.pBitmap))) - .__New() ; On deletion the buffer object will dispose of the bitmap. And it will decrement this.gdiplus. - return buffer + return ImagePut.BitmapBuffer(pBitmap) + } + + class BitmapBuffer { + __New(pBitmap) { + this.pBitmap := pBitmap + ImagePut.gdiplusStartup() + } + + __Delete() { + ImagePut.gdiplusShutdown("smart_pointer", this.pBitmap) + } } static put_screenshot(pBitmap, screenshot := "", alpha := "") { From dd9320d9f906e611ff24453ae441d06b4bf30018 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 7 Jan 2022 15:11:45 -0500 Subject: [PATCH 138/492] Extend ImagePutWindow with additional parameters --- ImagePut (for v1).ahk | 78 ++++++++++++++++++++++++++++--------------- ImagePut.ahk | 59 ++++++++++++++++++++------------ 2 files changed, 88 insertions(+), 49 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 83e7c2d6..9142e6e6 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -101,8 +101,11 @@ ImagePutWallpaper(image) { ; Puts the image in a window and returns a handle to a window. ; title - Window Title | string -> MyTitle ; pos - Window Coordinates | array -> [x,y,w,h] or [0,0] -ImagePutWindow(image, title := "", pos := "") { - return ImagePut("window", image, title, pos) +; style - Window Style | uint -> WS_VISIBLE +; styleEx - Window Extended Style | uint -> WS_EX_LAYERED +; parent - Window Parent | ptr -> hwnd +ImagePutWindow(image, title := "", pos := "", style := 0x82C80000, styleEx := 0x9, parent := "") { + return ImagePut("window", image, title, pos, style, styleEx, parent) } @@ -111,7 +114,7 @@ ImagePutWindow(image, title := "", pos := "") { ; style - Window Style | uint -> WS_VISIBLE ; styleEx - Window Extended Style | uint -> WS_EX_LAYERED ; parent - Window Parent | ptr -> hwnd -ImageShow(image, title := "", pos := "", style := 0x10000000, styleEx := 0x80088, parent := 0) { +ImageShow(image, title := "", pos := "", style := 0x10000000, styleEx := 0x80088, parent := "") { return ImagePut("show", image, title, pos, style, styleEx, parent) } @@ -535,9 +538,9 @@ class ImagePut { if (cotype = "show") return this.show(pBitmap, p1, p2, p3, p4, p5) - ; BitmapToCoimage("window", pBitmap, title, pos) + ; BitmapToCoimage("window", pBitmap, title, pos, style, styleEx, parent) if (cotype = "window") - return this.put_window(pBitmap, p1, p2) + return this.put_window(pBitmap, p1, p2, p3, p4, p5) ; BitmapToCoimage("desktop", pBitmap) if (cotype = "desktop") @@ -826,12 +829,20 @@ class ImagePut { Sleep (2**(A_Index-1) * 30) else throw Exception("Clipboard could not be opened.") - png := DllCall("RegisterClipboardFormat", "str", "png", "uint") - if !DllCall("IsClipboardFormatAvailable", "uint", png) - throw Exception("Clipboard does not have PNG stream data.") + for i, format in ["bmp", 6, "jpg", "gif"] { + if !(format ~= "^\d+$") + format := DllCall("RegisterClipboardFormat", "str", format, "uint") - if !(hData := DllCall("GetClipboardData", "uint", png, "ptr")) - throw Exception("Shared clipboard data has been deleted.") + if !DllCall("IsClipboardFormatAvailable", "uint", format) + continue + ;throw Exception("Clipboard does not have stream data.") + + if !(hData := DllCall("GetClipboardData", "uint", format, "ptr")) + throw Exception("Shared clipboard data has been deleted.") + } + + if !hData + Msgbox :( ; Allow the stream to be freed while leaving the hData intact. ; Please read: https://devblogs.microsoft.com/oldnewthing/20210930-00/?p=105745 @@ -1569,21 +1580,28 @@ class ImagePut { return [x,y,w,h] } - put_window(pBitmap, title := "", pos := "") { - WS_CAPTION := 0xC00000 - WS_CLIPCHILDREN := 0x2000000 - WS_EX_DLGMODALFRAME := 0x1 - WS_EX_TOPMOST := 0x8 - WS_EX_WINDOWEDGE := 0x100 + put_window(pBitmap, title := "", pos := "", style := 0x82C80000, styleEx := 0x9, parent := "") { + ; style := WS_POPUP | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU + ; styleEx := WS_EX_TOPMOST | WS_EX_DLGMODALFRAME + + ; WS_POPUP - Allows proper display of small windows. + ; WS_CLIPCHILDREN - Prevents redraw of dead pixels behind the child window. + ; WS_CAPTION - Titlebar. + ; WS_SYSMENU - Close button. Also sets the Alt+Space menu. + ; WS_EX_TOPMOST - Always on top. + ; WS_EX_DLGMODALFRAME - Removes the small icon in conjunction with A_ScriptHwnd as parent. + WS_POPUP := 0x80000000 + WS_CLIPCHILDREN := 0x2000000 + WS_CAPTION := 0xC00000 WS_SYSMENU := 0x80000 + WS_EX_TOPMOST := 0x8 + WS_EX_DLGMODALFRAME := 0x1 WS_CHILD := 0x40000000 WS_EX_LAYERED := 0x80000 WS_VISIBLE := 0x10000000 WS_EX_TOOLWINDOW := 0x80 - style := WS_CAPTION | WS_SYSMENU | WS_CLIPCHILDREN | WS_POPUP - styleEx := WS_EX_TOPMOST | WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME ; Get Bitmap width and height. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) @@ -1619,22 +1637,23 @@ class ImagePut { hwnd := DllCall("CreateWindowEx" , "uint", styleEx - , "str", this.WindowClass() ; lpClassName - , "str", title ; lpWindowName + , "str", this.WindowClass() ; lpClassName + , "str", title ; lpWindowName , "uint", style , "int", NumGet(rect, 0, "int") , "int", NumGet(rect, 4, "int") , "int", NumGet(rect, 8, "int") - NumGet(rect, 0, "int") , "int", NumGet(rect, 12, "int") - NumGet(rect, 4, "int") - , "ptr", A_ScriptHwnd ; hWndParent - , "ptr", 0 ; hMenu - , "ptr", 0 ; hInstance - , "ptr", 0 ; lpParam + , "ptr", (parent != "") ? parent : A_ScriptHwnd + , "ptr", 0 ; hMenu + , "ptr", 0 ; hInstance + , "ptr", 0 ; lpParam , "ptr") ; Tests have shown that changing the system default colors has no effect on F0F0F0. WinSet TransColor, % "F0F0F0", % "ahk_id" hwnd0 + ; A layered child window is only available on Windows 8+. this.show(pBitmap, title, [0, 0, w, h], WS_CHILD | WS_VISIBLE, WS_EX_LAYERED, hwnd) DllCall("ShowWindow", "ptr", hwnd, "int", 1) @@ -1642,7 +1661,12 @@ class ImagePut { return hwnd } - show(pBitmap, title := "", pos := "", style := 0x10000000, styleEx := 0x80088, parent := 0) { + show(pBitmap, title := "", pos := "", style := 0x10000000, styleEx := 0x80088, parent := "") { + ; WS_VISIBLE - Shows the window. + ; WS_EX_LAYERED - Must be set for UpdateLayeredWindow. + ; WS_EX_TOOLWINDOW - Hides from Alt+Tab. Removes small icon. + ; WS_EX_TOPMOST - Always on top. + ; Prevent the script from exiting early. void := ObjBindMethod({}, {}) Hotkey % "^+F12", % void, On @@ -1740,7 +1764,7 @@ class ImagePut { , "int", y , "int", w , "int", h - , "ptr", parent ? parent : 0 ; hWndParent + , "ptr", (parent != "") ? parent : A_ScriptHwnd , "ptr", 0 ; hMenu , "ptr", 0 ; hInstance , "ptr", 0 ; lpParam @@ -1763,7 +1787,7 @@ class ImagePut { DllCall("DeleteObject", "ptr", hbm) DllCall("DeleteDC", "ptr", hdc) - return hwnd0 + return hwnd } WindowClass() { diff --git a/ImagePut.ahk b/ImagePut.ahk index 6aec25e5..ea0428dd 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -101,8 +101,11 @@ ImagePutWallpaper(image) { ; Puts the image in a window and returns a handle to a window. ; title - Window Title | string -> MyTitle ; pos - Window Coordinates | array -> [x,y,w,h] or [0,0] -ImagePutWindow(image, title := "", pos := "") { - return ImagePut("window", image, title, pos) +; style - Window Style | uint -> WS_VISIBLE +; styleEx - Window Extended Style | uint -> WS_EX_LAYERED +; parent - Window Parent | ptr -> hwnd +ImagePutWindow(image, title := "", pos := "", style := 0x82C80000, styleEx := 0x9, parent := "") { + return ImagePut("window", image, title, pos, style, styleEx, parent) } @@ -111,7 +114,7 @@ ImagePutWindow(image, title := "", pos := "") { ; style - Window Style | uint -> WS_VISIBLE ; styleEx - Window Extended Style | uint -> WS_EX_LAYERED ; parent - Window Parent | ptr -> hwnd -ImageShow(image, title := "", pos := "", style := 0x10000000, styleEx := 0x80088, parent := 0) { +ImageShow(image, title := "", pos := "", style := 0x10000000, styleEx := 0x80088, parent := "") { return ImagePut("show", image, title, pos, style, styleEx, parent) } /* @@ -535,9 +538,9 @@ class ImagePut { if (cotype = "show") return this.show(pBitmap, p1, p2, p3, p4, p5) - ; BitmapToCoimage("window", pBitmap, title, pos) + ; BitmapToCoimage("window", pBitmap, title, pos, style, styleEx, parent) if (cotype = "window") - return this.put_window(pBitmap, p1, p2) + return this.put_window(pBitmap, p1, p2, p3, p4, p5) ; BitmapToCoimage("desktop", pBitmap) if (cotype = "desktop") @@ -1569,22 +1572,28 @@ class ImagePut { return [x,y,w,h] } - static put_window(pBitmap, title := "", pos := "") { - WS_CAPTION := 0xC00000 - WS_CLIPCHILDREN := 0x2000000 - WS_EX_DLGMODALFRAME := 0x1 - WS_EX_TOPMOST := 0x8 - WS_EX_WINDOWEDGE := 0x100 + static put_window(pBitmap, title := "", pos := "", style := 0x82C80000, styleEx := 0x9, parent := "") { + ; style := WS_POPUP | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU + ; styleEx := WS_EX_TOPMOST | WS_EX_DLGMODALFRAME + + ; WS_POPUP - Allows proper display of small windows. + ; WS_CLIPCHILDREN - Prevents redraw of dead pixels behind the child window. + ; WS_CAPTION - Titlebar. + ; WS_SYSMENU - Close button. Also sets the Alt+Space menu. + ; WS_EX_TOPMOST - Always on top. + ; WS_EX_DLGMODALFRAME - Removes the small icon in conjunction with A_ScriptHwnd as parent. + WS_POPUP := 0x80000000 + WS_CLIPCHILDREN := 0x2000000 + WS_CAPTION := 0xC00000 WS_SYSMENU := 0x80000 + WS_EX_TOPMOST := 0x8 + WS_EX_DLGMODALFRAME := 0x1 WS_CHILD := 0x40000000 WS_EX_LAYERED := 0x80000 WS_VISIBLE := 0x10000000 WS_EX_TOOLWINDOW := 0x80 - style := WS_CAPTION | WS_SYSMENU | WS_CLIPCHILDREN | WS_POPUP - styleEx := WS_EX_TOPMOST | WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME - ; Get Bitmap width and height. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) @@ -1619,22 +1628,23 @@ class ImagePut { hwnd := DllCall("CreateWindowEx" , "uint", styleEx - , "str", this.WindowClass() ; lpClassName - , "str", title ; lpWindowName + , "str", this.WindowClass() ; lpClassName + , "str", title ; lpWindowName , "uint", style , "int", NumGet(rect, 0, "int") , "int", NumGet(rect, 4, "int") , "int", NumGet(rect, 8, "int") - NumGet(rect, 0, "int") , "int", NumGet(rect, 12, "int") - NumGet(rect, 4, "int") - , "ptr", A_ScriptHwnd ; hWndParent - , "ptr", 0 ; hMenu - , "ptr", 0 ; hInstance - , "ptr", 0 ; lpParam + , "ptr", (parent != "") ? parent : A_ScriptHwnd + , "ptr", 0 ; hMenu + , "ptr", 0 ; hInstance + , "ptr", 0 ; lpParam , "ptr") ; Tests have shown that changing the system default colors has no effect on F0F0F0. WinSetTransColor "F0F0F0", hwnd + ; A layered child window is only available on Windows 8+. this.show(pBitmap, title, [0, 0, w, h], WS_CHILD | WS_VISIBLE, WS_EX_LAYERED, hwnd) DllCall("ShowWindow", "ptr", hwnd, "int", 1) @@ -1642,10 +1652,15 @@ class ImagePut { return hwnd } - static show(pBitmap, title := "", pos := "", style := 0x10000000, styleEx := 0x80088, parent := 0) { + static show(pBitmap, title := "", pos := "", style := 0x10000000, styleEx := 0x80088, parent := "") { + ; WS_VISIBLE - Shows the window. + ; WS_EX_LAYERED - Must be set for UpdateLayeredWindow. + ; WS_EX_TOOLWINDOW - Hides from Alt+Tab. Removes small icon. + ; WS_EX_TOPMOST - Always on top. ; Prevent the script from exiting early. Persistent(true) + ; Get Bitmap width and height. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) @@ -1740,7 +1755,7 @@ class ImagePut { , "int", y , "int", w , "int", h - , "ptr", parent ? parent : 0 ; hWndParent + , "ptr", (parent != "") ? parent : A_ScriptHwnd , "ptr", 0 ; hMenu , "ptr", 0 ; hInstance , "ptr", 0 ; lpParam From 2a8a722c27a81097edcfb162be3efa784ed1d8a8 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 7 Jan 2022 16:59:41 -0500 Subject: [PATCH 139/492] Revert clipboard stream changes --- ImagePut (for v1).ahk | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 9142e6e6..2eef9d79 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -829,20 +829,12 @@ class ImagePut { Sleep (2**(A_Index-1) * 30) else throw Exception("Clipboard could not be opened.") - for i, format in ["bmp", 6, "jpg", "gif"] { - if !(format ~= "^\d+$") - format := DllCall("RegisterClipboardFormat", "str", format, "uint") + png := DllCall("RegisterClipboardFormat", "str", "png", "uint") + if !DllCall("IsClipboardFormatAvailable", "uint", png) + throw Exception("Clipboard does not have PNG stream data.") - if !DllCall("IsClipboardFormatAvailable", "uint", format) - continue - ;throw Exception("Clipboard does not have stream data.") - - if !(hData := DllCall("GetClipboardData", "uint", format, "ptr")) - throw Exception("Shared clipboard data has been deleted.") - } - - if !hData - Msgbox :( + if !(hData := DllCall("GetClipboardData", "uint", png, "ptr")) + throw Exception("Shared clipboard data has been deleted.") ; Allow the stream to be freed while leaving the hData intact. ; Please read: https://devblogs.microsoft.com/oldnewthing/20210930-00/?p=105745 @@ -1602,7 +1594,6 @@ class ImagePut { WS_VISIBLE := 0x10000000 WS_EX_TOOLWINDOW := 0x80 - ; Get Bitmap width and height. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) From fbfb5da8442ffbff976b5fd1ecde20811e3b2f1c Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 7 Jan 2022 17:03:55 -0500 Subject: [PATCH 140/492] v1.5 --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 2eef9d79..a77acd02 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2,7 +2,7 @@ ; License: MIT License ; Author: Edison Hua (iseahound) ; Date: 2022-01-01 -; Version: 1.4.0 +; Version: 1.5.0 #Requires AutoHotkey v1.1.33+ diff --git a/ImagePut.ahk b/ImagePut.ahk index ea0428dd..b05bcb71 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2,7 +2,7 @@ ; License: MIT License ; Author: Edison Hua (iseahound) ; Date: 2022-01-01 -; Version: 1.4.0 +; Version: 1.5.0 #Requires AutoHotkey v2.0-beta.3+ From e4f00303cfefdb97264a1b0d2d3748719f2a20c9 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 8 Jan 2022 00:53:08 -0500 Subject: [PATCH 141/492] Fix ImageShow scaling on v1 --- ImagePut (for v1).ahk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index a77acd02..3887004e 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1721,7 +1721,7 @@ class ImagePut { ; Case 2: Image is scaled. else { ; Create a graphics context from the device context. - DllCall("gdiplus\GdipCreateFromHDC", "ptr", hdc , "ptr*", &pGraphics:=0) + DllCall("gdiplus\GdipCreateFromHDC", "ptr", hdc , "ptr*", pGraphics:=0) ; Set settings in graphics context. DllCall("gdiplus\GdipSetPixelOffsetMode", "ptr", pGraphics, "int", 2) ; Half pixel offset. From 91c23cbc13da6bad36303455c79b13ea0ef51ee8 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 8 Jan 2022 00:53:34 -0500 Subject: [PATCH 142/492] v1.5.1 --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 3887004e..8ae4d294 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2,7 +2,7 @@ ; License: MIT License ; Author: Edison Hua (iseahound) ; Date: 2022-01-01 -; Version: 1.5.0 +; Version: 1.5.1 #Requires AutoHotkey v1.1.33+ diff --git a/ImagePut.ahk b/ImagePut.ahk index b05bcb71..eff06b2a 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2,7 +2,7 @@ ; License: MIT License ; Author: Edison Hua (iseahound) ; Date: 2022-01-01 -; Version: 1.5.0 +; Version: 1.5.1 #Requires AutoHotkey v2.0-beta.3+ From 1564bddbdeb7c51c9620201bf02a7c21fd179241 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 9 Jan 2022 13:20:34 -0500 Subject: [PATCH 143/492] Cropped images cannot be zero width or height --- ImagePut (for v1).ahk | 37 +++++++++++++++++++------------------ ImagePut.ahk | 37 +++++++++++++++++++------------------ 2 files changed, 38 insertions(+), 36 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 8ae4d294..b4930e45 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -661,32 +661,33 @@ class ImagePut { DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", pBitmap, "int*", format:=0) + ; Abstraction Shift. + ; Previously, real values depended on abstract values. + ; Now, real values have been resolved, and abstract values depend on reals. + ; Are the numbers percentages? - crop[3] := (crop[3] ~= "%$") ? SubStr(crop[3], 1, -1) * 0.01 * width : crop[3] - crop[4] := (crop[4] ~= "%$") ? SubStr(crop[4], 1, -1) * 0.01 * height : crop[4] crop[1] := (crop[1] ~= "%$") ? SubStr(crop[1], 1, -1) * 0.01 * width : crop[1] crop[2] := (crop[2] ~= "%$") ? SubStr(crop[2], 1, -1) * 0.01 * height : crop[2] + crop[3] := (crop[3] ~= "%$") ? SubStr(crop[3], 1, -1) * 0.01 * width : crop[3] + crop[4] := (crop[4] ~= "%$") ? SubStr(crop[4], 1, -1) * 0.01 * height : crop[4] ; If numbers are negative, subtract the values from the edge. - crop[3] := (crop[3] < 0) ? width - Abs(crop[3]) - Abs(crop[1]) : crop[3] - crop[4] := (crop[4] < 0) ? height - Abs(crop[4]) - Abs(crop[2]) : crop[4] crop[1] := Abs(crop[1]) crop[2] := Abs(crop[2]) + crop[3] := (crop[3] < 0) ? width - Abs(crop[3]) - Abs(crop[1]) : crop[3] + crop[4] := (crop[4] < 0) ? height - Abs(crop[4]) - Abs(crop[2]) : crop[4] - ; Round to the nearest integer. - crop[3] := Round(crop[1] + crop[3]) - Round(crop[1]) ; A reminder that width and height - crop[4] := Round(crop[2] + crop[4]) - Round(crop[2]) ; are distances, not coordinates. - crop[1] := Round(crop[1]) ; so the abstract concept of a distance must be resolved - crop[2] := Round(crop[2]) ; into coordinates and then rounded and added up again. - - ; Variance Shift. Now place x,y before w,h because we are building abstracts from reals now. - ; Before we were resolving abstracts into real coordinates, now it's the opposite. - - ; Ensure that coordinates can never exceed the expected Bitmap area. - safe_x := (crop[1] > width) ? 0 : crop[1] ; Zero x if bigger. - safe_y := (crop[2] > height) ? 0 : crop[2] ; Zero y if bigger. - safe_w := (crop[1] + crop[3] > width) ? width - safe_x : crop[3] ; Max w if bigger. - safe_h := (crop[2] + crop[4] > height) ? height - safe_y : crop[4] ; Max h if bigger. + ; Round to the nearest integer. Reminder: width and height are distances, not coordinates. + safe_x := Round(crop[1]) + safe_y := Round(crop[2]) + safe_w := Round(crop[1] + crop[3]) - Round(crop[1]) + safe_h := Round(crop[2] + crop[4]) - Round(crop[2]) + + ; Minimum size is 1 x 1. Ensure that coordinates can never exceed the expected Bitmap area. + safe_x := (safe_x >= width) ? 0 : safe_x ; Default x is zero. + safe_y := (safe_y >= height) ? 0 : safe_y ; Default y is zero. + safe_w := (safe_w = 0 || safe_x + safe_w > width) ? width - safe_x : safe_w ; Default w is max width. + safe_h := (safe_h = 0 || safe_y + safe_h > height) ? height - safe_y : safe_h ; Default h is max height. ; Clone DllCall("gdiplus\GdipCloneBitmapAreaI" diff --git a/ImagePut.ahk b/ImagePut.ahk index eff06b2a..26533af2 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -661,32 +661,33 @@ class ImagePut { DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", pBitmap, "int*", &format:=0) + ; Abstraction Shift. + ; Previously, real values depended on abstract values. + ; Now, real values have been resolved, and abstract values depend on reals. + ; Are the numbers percentages? - crop[3] := (crop[3] ~= "%$") ? SubStr(crop[3], 1, -1) * 0.01 * width : crop[3] - crop[4] := (crop[4] ~= "%$") ? SubStr(crop[4], 1, -1) * 0.01 * height : crop[4] crop[1] := (crop[1] ~= "%$") ? SubStr(crop[1], 1, -1) * 0.01 * width : crop[1] crop[2] := (crop[2] ~= "%$") ? SubStr(crop[2], 1, -1) * 0.01 * height : crop[2] + crop[3] := (crop[3] ~= "%$") ? SubStr(crop[3], 1, -1) * 0.01 * width : crop[3] + crop[4] := (crop[4] ~= "%$") ? SubStr(crop[4], 1, -1) * 0.01 * height : crop[4] ; If numbers are negative, subtract the values from the edge. - crop[3] := (crop[3] < 0) ? width - Abs(crop[3]) - Abs(crop[1]) : crop[3] - crop[4] := (crop[4] < 0) ? height - Abs(crop[4]) - Abs(crop[2]) : crop[4] crop[1] := Abs(crop[1]) crop[2] := Abs(crop[2]) + crop[3] := (crop[3] < 0) ? width - Abs(crop[3]) - Abs(crop[1]) : crop[3] + crop[4] := (crop[4] < 0) ? height - Abs(crop[4]) - Abs(crop[2]) : crop[4] - ; Round to the nearest integer. - crop[3] := Round(crop[1] + crop[3]) - Round(crop[1]) ; A reminder that width and height - crop[4] := Round(crop[2] + crop[4]) - Round(crop[2]) ; are distances, not coordinates. - crop[1] := Round(crop[1]) ; so the abstract concept of a distance must be resolved - crop[2] := Round(crop[2]) ; into coordinates and then rounded and added up again. - - ; Variance Shift. Now place x,y before w,h because we are building abstracts from reals now. - ; Before we were resolving abstracts into real coordinates, now it's the opposite. + ; Round to the nearest integer. Reminder: width and height are distances, not coordinates. + safe_x := Round(crop[1]) + safe_y := Round(crop[2]) + safe_w := Round(crop[1] + crop[3]) - Round(crop[1]) + safe_h := Round(crop[2] + crop[4]) - Round(crop[2]) - ; Ensure that coordinates can never exceed the expected Bitmap area. - safe_x := (crop[1] > width) ? 0 : crop[1] ; Zero x if bigger. - safe_y := (crop[2] > height) ? 0 : crop[2] ; Zero y if bigger. - safe_w := (crop[1] + crop[3] > width) ? width - safe_x : crop[3] ; Max w if bigger. - safe_h := (crop[2] + crop[4] > height) ? height - safe_y : crop[4] ; Max h if bigger. + ; Minimum size is 1 x 1. Ensure that coordinates can never exceed the expected Bitmap area. + safe_x := (safe_x >= width) ? 0 : safe_x ; Default x is zero. + safe_y := (safe_y >= height) ? 0 : safe_y ; Default y is zero. + safe_w := (safe_w = 0 || safe_x + safe_w > width) ? width - safe_x : safe_w ; Default w is max width. + safe_h := (safe_h = 0 || safe_y + safe_h > height) ? height - safe_y : safe_h ; Default h is max height. ; Clone DllCall("gdiplus\GdipCloneBitmapAreaI" @@ -1660,7 +1661,7 @@ class ImagePut { ; Prevent the script from exiting early. Persistent(true) - + ; Get Bitmap width and height. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) From 81aafa57d53400bcbef38b9ac04b994327944bf1 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 9 Jan 2022 13:36:23 -0500 Subject: [PATCH 144/492] Avoid cropping when identical to the source image --- ImagePut (for v1).ahk | 4 ++++ ImagePut.ahk | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index b4930e45..db1ebe90 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -689,6 +689,10 @@ class ImagePut { safe_w := (safe_w = 0 || safe_x + safe_w > width) ? width - safe_x : safe_w ; Default w is max width. safe_h := (safe_h = 0 || safe_y + safe_h > height) ? height - safe_y : safe_h ; Default h is max height. + ; Avoid cropping if no changes are detected. + if (safe_x = 0 && safe_y = 0 && safe_w = width && safe_h = height) + return pBitmap + ; Clone DllCall("gdiplus\GdipCloneBitmapAreaI" , "int", safe_x diff --git a/ImagePut.ahk b/ImagePut.ahk index 26533af2..ce75c33c 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -689,6 +689,10 @@ class ImagePut { safe_w := (safe_w = 0 || safe_x + safe_w > width) ? width - safe_x : safe_w ; Default w is max width. safe_h := (safe_h = 0 || safe_y + safe_h > height) ? height - safe_y : safe_h ; Default h is max height. + ; Avoid cropping if no changes are detected. + if (safe_x = 0 && safe_y = 0 && safe_w = width && safe_h = height) + return pBitmap + ; Clone DllCall("gdiplus\GdipCloneBitmapAreaI" , "int", safe_x From 6109bb03cac6dad9a90de62ab5a91bdffe5407ec Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 9 Jan 2022 14:35:31 -0500 Subject: [PATCH 145/492] Reduce minimum string lengths for base64 and hex data --- ImagePut (for v1).ahk | 4 ++-- ImagePut.ahk | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index db1ebe90..52968847 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -398,11 +398,11 @@ class ImagePut { return "file" ; A "hex" string is binary image data encoded into text using hexadecimal. - if (StrLen(image) >= 116) && (image ~= "(?i)^\s*(0x)?[0-9a-f]+\s*$") + if (StrLen(image) >= 48) && (image ~= "(?i)^\s*(0x)?[0-9a-f]+\s*$") return "hex" ; A "base64" string is binary image data encoded into text using standard 64 characters. - if (StrLen(image) >= 80) && (image ~= "^\s*(?:data:image\/[a-z]+;base64,)?" + if (StrLen(image) >= 32) && (image ~= "^\s*(?:data:image\/[a-z]+;base64,)?" . "(?:[A-Za-z0-9+\/]{4})*+(?:[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{2}==)?\s*$") return "base64" diff --git a/ImagePut.ahk b/ImagePut.ahk index ce75c33c..e45b3b4d 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -398,11 +398,11 @@ class ImagePut { return "file" ; A "hex" string is binary image data encoded into text using hexadecimal. - if (StrLen(image) >= 116) && (image ~= "(?i)^\s*(0x)?[0-9a-f]+\s*$") + if (StrLen(image) >= 48) && (image ~= "(?i)^\s*(0x)?[0-9a-f]+\s*$") return "hex" ; A "base64" string is binary image data encoded into text using standard 64 characters. - if (StrLen(image) >= 80) && (image ~= "^\s*(?:data:image\/[a-z]+;base64,)?" + if (StrLen(image) >= 32) && (image ~= "^\s*(?:data:image\/[a-z]+;base64,)?" . "(?:[A-Za-z0-9+\/]{4})*+(?:[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{2}==)?\s*$") return "base64" From 4aa5f398a415b74f5281c359d2200af813057158 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 9 Jan 2022 16:20:41 -0500 Subject: [PATCH 146/492] Document RandomAccessStream has an internal stream --- ImagePut (for v1).ahk | 4 ++-- ImagePut.ahk | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 52968847..f3fbd26d 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -398,7 +398,7 @@ class ImagePut { return "file" ; A "hex" string is binary image data encoded into text using hexadecimal. - if (StrLen(image) >= 48) && (image ~= "(?i)^\s*(0x)?[0-9a-f]+\s*$") + if (StrLen(image) >= 48) && (image ~= "^\s*(?:[A-Fa-f0-9]{2})*+\s*$") return "hex" ; A "base64" string is binary image data encoded into text using standard 64 characters. @@ -1404,7 +1404,7 @@ class ImagePut { } get_RandomAccessStream(image) { - ; Note that the returned stream shares a reference count with the original RandomAccessStream. + ; Note that the returned stream shares a reference count with the original RandomAccessStream's internal stream. DllCall("ole32\CLSIDFromString", "wstr", "{0000000C-0000-0000-C000-000000000046}", "ptr", &CLSID := VarSetCapacity(CLSID, 16), "uint") DllCall("ShCore\CreateStreamOverRandomAccessStream", "ptr", image, "ptr", &CLSID, "ptr*", pStream:=0, "uint") return pStream diff --git a/ImagePut.ahk b/ImagePut.ahk index e45b3b4d..0d000f2d 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1404,7 +1404,7 @@ class ImagePut { } static get_RandomAccessStream(image) { - ; Note that the returned stream shares a reference count with the original RandomAccessStream. + ; Note that the returned stream shares a reference count with the original RandomAccessStream's internal stream. DllCall("ole32\CLSIDFromString", "wstr", "{0000000C-0000-0000-C000-000000000046}", "ptr", CLSID := Buffer(16), "HRESULT") DllCall("ShCore\CreateStreamOverRandomAccessStream", "ptr", image, "ptr", CLSID, "ptr*", &pStream:=0, "HRESULT") return pStream From 53a73e641c4329b0010b8ef09cb9fa1fbd8a45a2 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 9 Jan 2022 16:22:32 -0500 Subject: [PATCH 147/492] Improve hex string RegEx to check divisibility by 2 --- ImagePut.ahk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index 0d000f2d..23e614a9 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -398,7 +398,7 @@ class ImagePut { return "file" ; A "hex" string is binary image data encoded into text using hexadecimal. - if (StrLen(image) >= 48) && (image ~= "(?i)^\s*(0x)?[0-9a-f]+\s*$") + if (StrLen(image) >= 48) && (image ~= "^\s*(?:[A-Fa-f0-9]{2})*+\s*$") return "hex" ; A "base64" string is binary image data encoded into text using standard 64 characters. From bf8fbe039f68d41745c75d175f05021b400716ba Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 9 Jan 2022 22:46:50 -0500 Subject: [PATCH 148/492] Better error message for invalid PDF --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index f3fbd26d..b14c90aa 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1053,7 +1053,7 @@ class ImagePut { DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", &signature := VarSetCapacity(signature, 4), "uint", 4, "uint") StrPut("%PDF", &magic := VarSetCapacity(magic, 4), "CP0") if 4 > DllCall("ntdll\RtlCompareMemory", "ptr", &signature, "ptr", &magic, "uptr", 4, "uptr") - throw Exception("Could not be loaded from a valid file path or URL.") + throw Exception("Invalid PDF.") ; Create a RandomAccessStream with BSOS_PREFERDESTINATIONSTREAM. DllCall("ole32\CLSIDFromString", "wstr", "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}", "ptr", &CLSID := VarSetCapacity(CLSID, 16), "uint") diff --git a/ImagePut.ahk b/ImagePut.ahk index 23e614a9..0ffdadf4 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1053,7 +1053,7 @@ class ImagePut { DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", signature := Buffer(4), "uint", 4, "HRESULT") StrPut("%PDF", magic := Buffer(4), "CP0") if 4 > DllCall("ntdll\RtlCompareMemory", "ptr", signature, "ptr", magic, "uptr", 4, "uptr") - throw Error("Could not be loaded from a valid file path or URL.") + throw Error("Invalid PDF.") ; Create a RandomAccessStream with BSOS_PREFERDESTINATIONSTREAM. DllCall("ole32\CLSIDFromString", "wstr", "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}", "ptr", CLSID := Buffer(16), "HRESULT") From 727d49bbe03236fd2ff56e6693837770f7503238 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 9 Jan 2022 22:56:26 -0500 Subject: [PATCH 149/492] System.Drawing Rectangle --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index b14c90aa..aca17e6f 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2488,7 +2488,7 @@ class ImageEqual extends ImagePut { , "ptr*", pBitmap%A_Index%:=0) throw Exception("Cloning Bitmap" A_Index " failed.") - ; struct RECT - https://docs.microsoft.com/en-us/windows/win32/api/windef/ns-windef-rect + ; struct RECT - https://referencesource.microsoft.com/#System.Drawing/commonui/System/Drawing/Rectangle.cs,32 VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 NumPut( width1, Rect, 8, "uint") ; Width NumPut( height1, Rect, 12, "uint") ; Height diff --git a/ImagePut.ahk b/ImagePut.ahk index 0ffdadf4..0a2a2e6a 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2488,7 +2488,7 @@ class ImageEqual extends ImagePut { , "ptr*", &pBitmap%A_Index%:=0) throw Error("Cloning Bitmap" A_Index " failed.") - ; struct RECT - https://docs.microsoft.com/en-us/windows/win32/api/windef/ns-windef-rect + ; struct RECT - https://referencesource.microsoft.com/#System.Drawing/commonui/System/Drawing/Rectangle.cs,32 Rect := Buffer(16, 0) ; sizeof(Rect) = 16 NumPut( "uint", width1, Rect, 8) ; Width NumPut( "uint", height1, Rect, 12) ; Height From d7cf7054567e6fde1d1a3ad84f5579930a36f6e9 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 17 Jan 2022 01:09:58 -0500 Subject: [PATCH 150/492] better error message --- ImagePut (for v1).ahk | 6 +++--- ImagePut.ahk | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index aca17e6f..145f6dd9 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2462,11 +2462,11 @@ class ImageEqual extends ImagePut { DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", SourceBitmap1, "int*", format1:=0) DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", SourceBitmap2, "int*", format2:=0) - ; Dimensions must be non-zero. + ; Determine if get width and height failed (as dimensions can never be zero). if !(width1 && width2 && height1 && height2) - throw Exception("The bitmap dimensions cannot be zero.") + throw Exception("Get bitmap width and height failed.") - ; Match bitmap dimensions. + ; Dimensions must be equal. if (width1 != width2 || height1 != height2) return false diff --git a/ImagePut.ahk b/ImagePut.ahk index 0a2a2e6a..9c55f24d 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2462,11 +2462,11 @@ class ImageEqual extends ImagePut { DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", SourceBitmap1, "int*", &format1:=0) DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", SourceBitmap2, "int*", &format2:=0) - ; Dimensions must be non-zero. + ; Determine if get width and height failed (as dimensions can never be zero). if !(width1 && width2 && height1 && height2) - throw Error("The bitmap dimensions cannot be zero.") + throw Error("Get bitmap width and height failed.") - ; Match bitmap dimensions. + ; Dimensions must be equal. if (width1 != width2 || height1 != height2) return false From b12584f62193721e8b265456408ca42b2ca59ba1 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 19 Jan 2022 11:38:18 -0500 Subject: [PATCH 151/492] confusing comment about file extensions --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 145f6dd9..2158c792 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2237,7 +2237,7 @@ class ImagePut { if (extension == "" && filename ~= "^(?i:bmp|dib|rle|jpg|jpeg|jpe|jfif|gif|tif|tiff|png)$") extension := filename, filename := "" - ; Append an invalid extension to the filename. + ; An invalid extension is actually part of the filename. if !(extension ~= "^(?i:bmp|dib|rle|jpg|jpeg|jpe|jfif|gif|tif|tiff|png)$") { if (extension != "") filename .= "." extension diff --git a/ImagePut.ahk b/ImagePut.ahk index 9c55f24d..a84dc2f4 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2237,7 +2237,7 @@ class ImagePut { if (extension == "" && filename ~= "^(?i:bmp|dib|rle|jpg|jpeg|jpe|jfif|gif|tif|tiff|png)$") extension := filename, filename := "" - ; Append an invalid extension to the filename. + ; An invalid extension is actually part of the filename. if !(extension ~= "^(?i:bmp|dib|rle|jpg|jpeg|jpe|jfif|gif|tif|tiff|png)$") { if (extension != "") filename .= "." extension From 08426291188e3a6cc68f4b55a1d0a9501af54a47 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 19 Jan 2022 11:38:48 -0500 Subject: [PATCH 152/492] comment about invalid file extensions From dcb319bdc1737a1057d1419b673e92432e333f53 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 19 Jan 2022 11:39:52 -0500 Subject: [PATCH 153/492] Add Github --- ImagePut (for v1).ahk | 1 + ImagePut.ahk | 1 + 2 files changed, 2 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 2158c792..a87dfb8d 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1,6 +1,7 @@ ; Script: ImagePut.ahk ; License: MIT License ; Author: Edison Hua (iseahound) +; Github: https://github.com/iseahound/ImagePut ; Date: 2022-01-01 ; Version: 1.5.1 diff --git a/ImagePut.ahk b/ImagePut.ahk index a84dc2f4..681e2127 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1,6 +1,7 @@ ; Script: ImagePut.ahk ; License: MIT License ; Author: Edison Hua (iseahound) +; Github: https://github.com/iseahound/ImagePut ; Date: 2022-01-01 ; Version: 1.5.1 From ec1856bc0d843dd5d368192a31fa876e1b89c428 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 19 Jan 2022 12:02:19 -0500 Subject: [PATCH 154/492] Enable Double Clicking via CS_DBLCLKS --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index a87dfb8d..c15293b4 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1805,7 +1805,7 @@ class ImagePut { ; struct tagWNDCLASSEXW - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexw _ := (A_PtrSize = 4) NumPut( size, wc, 0, "uint") ; cbSize - NumPut( 0, wc, 4, "uint") ; style + NumPut( 0x8, wc, 4, "uint") ; style NumPut( pWndProc, wc, 8, "ptr") ; lpfnWndProc NumPut( 0, wc, _ ? 12:16, "int") ; cbClsExtra NumPut( 0, wc, _ ? 16:20, "int") ; cbWndExtra diff --git a/ImagePut.ahk b/ImagePut.ahk index 681e2127..4adfceed 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1805,7 +1805,7 @@ class ImagePut { ; struct tagWNDCLASSEXW - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexw _ := (A_PtrSize = 4) NumPut( "uint", wc.size, wc, 0) ; cbSize - NumPut( "uint", 0, wc, 4) ; style + NumPut( "uint", 0x8, wc, 4) ; style NumPut( "ptr", pWndProc, wc, 8) ; lpfnWndProc NumPut( "int", 0, wc, _ ? 12:16) ; cbClsExtra NumPut( "int", 0, wc, _ ? 16:20) ; cbWndExtra From 849770b362a63123ec4d9b4ac9a5fe45097d7c4f Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 19 Jan 2022 12:04:13 -0500 Subject: [PATCH 155/492] Make WindowClass() more generic --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index c15293b4..b5b14c39 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1788,7 +1788,7 @@ class ImagePut { } WindowClass() { - ; The class name is ImagePut. + ; The window class shares the name of this class. cls := this.__class VarSetCapacity(wc, size := _ ? 48:80) ; sizeof(WNDCLASSEX) = 48, 80 diff --git a/ImagePut.ahk b/ImagePut.ahk index 4adfceed..91d3ce69 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1788,7 +1788,7 @@ class ImagePut { } static WindowClass() { - ; The class name is ImagePut. + ; The window class shares the name of this class. cls := this.prototype.__class wc := Buffer(A_PtrSize = 4 ? 48:80) ; sizeof(WNDCLASSEX) = 48, 80 From 4cb6625b7bbab3c79660ffc77dc0ca113ffebf28 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 19 Jan 2022 13:04:47 -0500 Subject: [PATCH 156/492] Fix incorrect window width & height --- ImagePut (for v1).ahk | 18 +++++++++++------- ImagePut.ahk | 18 +++++++++++------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index b5b14c39..39c4159e 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -115,7 +115,7 @@ ImagePutWindow(image, title := "", pos := "", style := 0x82C80000, styleEx := 0x ; style - Window Style | uint -> WS_VISIBLE ; styleEx - Window Extended Style | uint -> WS_EX_LAYERED ; parent - Window Parent | ptr -> hwnd -ImageShow(image, title := "", pos := "", style := 0x10000000, styleEx := 0x80088, parent := "") { +ImageShow(image, title := "", pos := "", style := 0x90000000, styleEx := 0x80088, parent := "") { return ImagePut("show", image, title, pos, style, styleEx, parent) } @@ -1658,11 +1658,15 @@ class ImagePut { return hwnd } - show(pBitmap, title := "", pos := "", style := 0x10000000, styleEx := 0x80088, parent := "") { - ; WS_VISIBLE - Shows the window. - ; WS_EX_LAYERED - Must be set for UpdateLayeredWindow. - ; WS_EX_TOOLWINDOW - Hides from Alt+Tab. Removes small icon. - ; WS_EX_TOPMOST - Always on top. + show(pBitmap, title := "", pos := "", style := 0x90000000, styleEx := 0x80088, parent := "") { + ; Window Styles - https://docs.microsoft.com/en-us/windows/win32/winmsg/window-styles + WS_POPUP := 0x80000000 ; Allow small windows. + WS_VISIBLE := 0x10000000 ; Show on creation. + + ; Extended Window Styles - https://docs.microsoft.com/en-us/windows/win32/winmsg/extended-window-styles + WS_EX_TOPMOST := 0x8 ; Always on top. + WS_EX_TOOLWINDOW := 0x80 ; Hides from Alt+Tab menu. Removes small icon. + WS_EX_LAYERED := 0x80000 ; For UpdateLayeredWindow. ; Prevent the script from exiting early. void := ObjBindMethod({}, {}) @@ -1753,7 +1757,7 @@ class ImagePut { } hwnd := DllCall("CreateWindowEx" - , "uint", styleEx | 0x80000 ; dwExStyle + , "uint", styleEx | WS_EX_LAYERED ; dwExStyle , "str", this.WindowClass() ; lpClassName , "str", title ; lpWindowName , "uint", style ; dwStyle diff --git a/ImagePut.ahk b/ImagePut.ahk index 91d3ce69..11bd94dc 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -115,7 +115,7 @@ ImagePutWindow(image, title := "", pos := "", style := 0x82C80000, styleEx := 0x ; style - Window Style | uint -> WS_VISIBLE ; styleEx - Window Extended Style | uint -> WS_EX_LAYERED ; parent - Window Parent | ptr -> hwnd -ImageShow(image, title := "", pos := "", style := 0x10000000, styleEx := 0x80088, parent := "") { +ImageShow(image, title := "", pos := "", style := 0x90000000, styleEx := 0x80088, parent := "") { return ImagePut("show", image, title, pos, style, styleEx, parent) } /* @@ -1658,11 +1658,15 @@ class ImagePut { return hwnd } - static show(pBitmap, title := "", pos := "", style := 0x10000000, styleEx := 0x80088, parent := "") { - ; WS_VISIBLE - Shows the window. - ; WS_EX_LAYERED - Must be set for UpdateLayeredWindow. - ; WS_EX_TOOLWINDOW - Hides from Alt+Tab. Removes small icon. - ; WS_EX_TOPMOST - Always on top. + static show(pBitmap, title := "", pos := "", style := 0x90000000, styleEx := 0x80088, parent := "") { + ; Window Styles - https://docs.microsoft.com/en-us/windows/win32/winmsg/window-styles + WS_POPUP := 0x80000000 ; Allow small windows. + WS_VISIBLE := 0x10000000 ; Show on creation. + + ; Extended Window Styles - https://docs.microsoft.com/en-us/windows/win32/winmsg/extended-window-styles + WS_EX_TOPMOST := 0x8 ; Always on top. + WS_EX_TOOLWINDOW := 0x80 ; Hides from Alt+Tab menu. Removes small icon. + WS_EX_LAYERED := 0x80000 ; For UpdateLayeredWindow. ; Prevent the script from exiting early. Persistent(true) @@ -1753,7 +1757,7 @@ class ImagePut { } hwnd := DllCall("CreateWindowEx" - , "uint", styleEx | 0x80000 ; dwExStyle + , "uint", styleEx | WS_EX_LAYERED ; dwExStyle , "str", this.WindowClass() ; lpClassName , "str", title ; lpWindowName , "uint", style ; dwStyle From 8953f3e77c545366d7447a24c93bc3d17b9c876e Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 19 Jan 2022 13:22:51 -0500 Subject: [PATCH 157/492] Prettify Window Styles --- ImagePut (for v1).ahk | 35 +++++++++++++++-------------------- ImagePut.ahk | 35 +++++++++++++++-------------------- 2 files changed, 30 insertions(+), 40 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 39c4159e..ad3ee716 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1579,26 +1579,21 @@ class ImagePut { } put_window(pBitmap, title := "", pos := "", style := 0x82C80000, styleEx := 0x9, parent := "") { - ; style := WS_POPUP | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU - ; styleEx := WS_EX_TOPMOST | WS_EX_DLGMODALFRAME - - ; WS_POPUP - Allows proper display of small windows. - ; WS_CLIPCHILDREN - Prevents redraw of dead pixels behind the child window. - ; WS_CAPTION - Titlebar. - ; WS_SYSMENU - Close button. Also sets the Alt+Space menu. - ; WS_EX_TOPMOST - Always on top. - ; WS_EX_DLGMODALFRAME - Removes the small icon in conjunction with A_ScriptHwnd as parent. - - WS_POPUP := 0x80000000 - WS_CLIPCHILDREN := 0x2000000 - WS_CAPTION := 0xC00000 - WS_SYSMENU := 0x80000 - WS_EX_TOPMOST := 0x8 - WS_EX_DLGMODALFRAME := 0x1 - WS_CHILD := 0x40000000 - WS_EX_LAYERED := 0x80000 - WS_VISIBLE := 0x10000000 - WS_EX_TOOLWINDOW := 0x80 + ; Window Styles - https://docs.microsoft.com/en-us/windows/win32/winmsg/window-styles + ; Extended Window Styles - https://docs.microsoft.com/en-us/windows/win32/winmsg/extended-window-styles + + ; Parent Window + WS_POPUP := 0x80000000 ; Allow small windows. + WS_CLIPCHILDREN := 0x2000000 ; Prevents redraw of pixels covered by child windows. + WS_CAPTION := 0xC00000 ; Titlebar. + WS_SYSMENU := 0x80000 ; Close button. Comes with Alt+Space menu. + WS_EX_TOPMOST := 0x8 ; Always on top. + WS_EX_DLGMODALFRAME := 0x1 ; Removes small icon in titlebar with A_ScriptHwnd as parent. + + ; Child Window + WS_CHILD := 0x40000000 ; Creates a child window. + WS_VISIBLE := 0x10000000 ; Show on creation. + WS_EX_LAYERED := 0x80000 ; For UpdateLayeredWindow. ; Get Bitmap width and height. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) diff --git a/ImagePut.ahk b/ImagePut.ahk index 11bd94dc..cae690f5 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1579,26 +1579,21 @@ class ImagePut { } static put_window(pBitmap, title := "", pos := "", style := 0x82C80000, styleEx := 0x9, parent := "") { - ; style := WS_POPUP | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU - ; styleEx := WS_EX_TOPMOST | WS_EX_DLGMODALFRAME - - ; WS_POPUP - Allows proper display of small windows. - ; WS_CLIPCHILDREN - Prevents redraw of dead pixels behind the child window. - ; WS_CAPTION - Titlebar. - ; WS_SYSMENU - Close button. Also sets the Alt+Space menu. - ; WS_EX_TOPMOST - Always on top. - ; WS_EX_DLGMODALFRAME - Removes the small icon in conjunction with A_ScriptHwnd as parent. - - WS_POPUP := 0x80000000 - WS_CLIPCHILDREN := 0x2000000 - WS_CAPTION := 0xC00000 - WS_SYSMENU := 0x80000 - WS_EX_TOPMOST := 0x8 - WS_EX_DLGMODALFRAME := 0x1 - WS_CHILD := 0x40000000 - WS_EX_LAYERED := 0x80000 - WS_VISIBLE := 0x10000000 - WS_EX_TOOLWINDOW := 0x80 + ; Window Styles - https://docs.microsoft.com/en-us/windows/win32/winmsg/window-styles + ; Extended Window Styles - https://docs.microsoft.com/en-us/windows/win32/winmsg/extended-window-styles + + ; Parent Window + WS_POPUP := 0x80000000 ; Allow small windows. + WS_CLIPCHILDREN := 0x2000000 ; Prevents redraw of pixels covered by child windows. + WS_CAPTION := 0xC00000 ; Titlebar. + WS_SYSMENU := 0x80000 ; Close button. Comes with Alt+Space menu. + WS_EX_TOPMOST := 0x8 ; Always on top. + WS_EX_DLGMODALFRAME := 0x1 ; Removes small icon in titlebar with A_ScriptHwnd as parent. + + ; Child Window + WS_CHILD := 0x40000000 ; Creates a child window. + WS_VISIBLE := 0x10000000 ; Show on creation. + WS_EX_LAYERED := 0x80000 ; For UpdateLayeredWindow. ; Get Bitmap width and height. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) From 7520670917967b702026f58a0c9516a87bcbca6e Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 25 Jan 2022 17:46:48 -0500 Subject: [PATCH 158/492] Convert forward slashes into windows backslash --- ImagePut (for v1).ahk | 3 +++ ImagePut.ahk | 3 +++ 2 files changed, 6 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index ad3ee716..e0223223 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2212,6 +2212,9 @@ class ImagePut { ; Save default extension. default := extension + ; Convert forward style slashes into Windows style backslashes. + filepath := RegExReplace(filepath, "/", "\") + ; Split the filepath. SplitPath % Trim(filepath),, directory, extension, filename diff --git a/ImagePut.ahk b/ImagePut.ahk index cae690f5..397469a3 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2212,6 +2212,9 @@ class ImagePut { ; Save default extension. default := extension + ; Convert forward style slashes into Windows style backslashes. + filepath := RegExReplace(filepath, "/", "\") + ; Split the filepath. SplitPath Trim(filepath),, &directory, &extension, &filename From 158cf5cdafc320d2d6e0d5ad0f9291d97b7bfdfa Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 26 Jan 2022 16:09:03 -0500 Subject: [PATCH 159/492] Fix transparency in put_window on v1 --- ImagePut (for v1).ahk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index e0223223..cb0134ec 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1643,7 +1643,7 @@ class ImagePut { , "ptr") ; Tests have shown that changing the system default colors has no effect on F0F0F0. - WinSet TransColor, % "F0F0F0", % "ahk_id" hwnd0 + WinSet TransColor, % "F0F0F0", % "ahk_id" hwnd ; A layered child window is only available on Windows 8+. this.show(pBitmap, title, [0, 0, w, h], WS_CHILD | WS_VISIBLE, WS_EX_LAYERED, hwnd) From b3e943ce51ed5889f3b44660d2840aa68edfec19 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 26 Jan 2022 17:17:42 -0500 Subject: [PATCH 160/492] GetClassInfoEx requires a non-null module handle --- ImagePut (for v1).ahk | 5 +++-- ImagePut.ahk | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index cb0134ec..16fafca8 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1789,10 +1789,11 @@ class ImagePut { WindowClass() { ; The window class shares the name of this class. cls := this.__class - VarSetCapacity(wc, size := _ ? 48:80) ; sizeof(WNDCLASSEX) = 48, 80 + VarSetCapacity(wc, size := A_PtrSize = 4 ? 48:80) ; sizeof(WNDCLASSEX) = 48, 80 ; Check if the window class is already registered. - if DllCall("GetClassInfoEx", "ptr", 0, "str", cls, "ptr", wc) + hInstance := DllCall("GetModuleHandle", "ptr", 0, "ptr") + if DllCall("GetClassInfoEx", "ptr", hInstance, "str", cls, "ptr", &wc) return cls ; Create window data. diff --git a/ImagePut.ahk b/ImagePut.ahk index 397469a3..04aa2f50 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1789,10 +1789,11 @@ class ImagePut { static WindowClass() { ; The window class shares the name of this class. cls := this.prototype.__class - wc := Buffer(A_PtrSize = 4 ? 48:80) ; sizeof(WNDCLASSEX) = 48, 80 + wc := Buffer(A_PtrSize = 4 ? 48:80) ; sizeof(WNDCLASSEX) = 48, 80 ; Check if the window class is already registered. - if DllCall("GetClassInfoEx", "ptr", 0, "str", cls, "ptr", wc) + hInstance := DllCall("GetModuleHandle", "ptr", 0, "ptr") + if DllCall("GetClassInfoEx", "ptr", hInstance, "str", cls, "ptr", wc) return cls ; Create window data. From 7eb710769bd9f49057cb151978659fbb40b2f339 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 26 Jan 2022 18:14:53 -0500 Subject: [PATCH 161/492] Fully fix color key transparency --- ImagePut (for v1).ahk | 4 +++- ImagePut.ahk | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 16fafca8..8ad4dd01 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1643,7 +1643,9 @@ class ImagePut { , "ptr") ; Tests have shown that changing the system default colors has no effect on F0F0F0. - WinSet TransColor, % "F0F0F0", % "ahk_id" hwnd + ; Must call SetWindowLong with WS_EX_LAYERED immediately before SetLayeredWindowAttributes. + DllCall("SetWindowLong", "ptr", hwnd, "int", -20, "int", styleEx | WS_EX_LAYERED) + DllCall("SetLayeredWindowAttributes", "ptr", hwnd, "uint", 0xF0F0F0, "uchar", 0, "int", 1) ; A layered child window is only available on Windows 8+. this.show(pBitmap, title, [0, 0, w, h], WS_CHILD | WS_VISIBLE, WS_EX_LAYERED, hwnd) diff --git a/ImagePut.ahk b/ImagePut.ahk index 04aa2f50..920d64f2 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1643,7 +1643,9 @@ class ImagePut { , "ptr") ; Tests have shown that changing the system default colors has no effect on F0F0F0. - WinSetTransColor "F0F0F0", hwnd + ; Must call SetWindowLong with WS_EX_LAYERED immediately before SetLayeredWindowAttributes. + DllCall("SetWindowLong", "ptr", hwnd, "int", -20, "int", styleEx | WS_EX_LAYERED) + DllCall("SetLayeredWindowAttributes", "ptr", hwnd, "uint", 0xF0F0F0, "uchar", 0, "int", 1) ; A layered child window is only available on Windows 8+. this.show(pBitmap, title, [0, 0, w, h], WS_CHILD | WS_VISIBLE, WS_EX_LAYERED, hwnd) From e5d8b357229b997ef5ca45418dcd681c24a8a9d7 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 26 Jan 2022 18:35:40 -0500 Subject: [PATCH 162/492] Fix from_dc selecting hbm to multiple DC --- ImagePut (for v1).ahk | 70 +++++++++++++++++++++++++++++++++++++++++-- ImagePut.ahk | 70 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 134 insertions(+), 6 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 8ad4dd01..4e982b93 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1225,9 +1225,73 @@ class ImagePut { } from_dc(image) { - if !(hbm := DllCall("GetCurrentObject", "ptr", image, "uint", 7)) + ; An application cannot select a single bitmap into more than one DC at a time. + if !(sbm := DllCall("GetCurrentObject", "ptr", image, "uint", 7)) throw Exception("The device context has no bitmap selected.") - return this.from_hBitmap(hbm) + + ; struct DIBSECTION - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-dibsection + ; struct BITMAP - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmap + VarSetCapacity(dib, size := 64+5*A_PtrSize) ; sizeof(DIBSECTION) = 84, 104 + DllCall("GetObject", "ptr", sbm, "int", size, "ptr", &dib) + , width := NumGet(dib, 4, "uint") + , height := NumGet(dib, 8, "uint") + , bpp := NumGet(dib, 18, "ushort") + , pBits := NumGet(dib, A_PtrSize = 4 ? 20:24, "ptr") + + ; Fallback to built-in method if pixels are not 32-bit ARGB or hBitmap is a device dependent bitmap. + if (pBits = 0 || bpp != 32) { ; This built-in version is 120% faster but ignores transparency. + DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "ptr", sbm, "ptr", 0, "ptr*", pBitmap:=0) + return pBitmap + } + + ; Create a device independent bitmap with negative height. All DIBs use the screen pixel format (pARGB). + ; Use hbm to buffer the image such that top-down and bottom-up images are mapped to this top-down buffer. + ; pBits is the pointer to (top-down) pixel values. The Scan0 will point to the pBits. + ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader + hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") + VarSetCapacity(bi, 40, 0) ; sizeof(bi) = 40 + NumPut( 40, bi, 0, "uint") ; Size + NumPut( width, bi, 4, "uint") ; Width + NumPut( -height, bi, 8, "int") ; Height - Negative so (0, 0) is top-left. + NumPut( 1, bi, 12, "ushort") ; Planes + NumPut( 32, bi, 14, "ushort") ; BitCount / BitsPerPixel + hbm := DllCall("CreateDIBSection", "ptr", hdc, "ptr", &bi, "uint", 0, "ptr*", pBits:=0, "ptr", 0, "uint", 0, "ptr") + obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") + + ; This is the 32-bit ARGB pBitmap (different from an hBitmap) that will receive the final converted pixels. + DllCall("gdiplus\GdipCreateBitmapFromScan0" + , "int", width, "int", height, "int", 0, "int", 0x26200A, "ptr", 0, "ptr*", pBitmap:=0) + + ; Create a Scan0 buffer pointing to pBits. The buffer has pixel format pARGB. + VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 + NumPut( width, Rect, 8, "uint") ; Width + NumPut( height, Rect, 12, "uint") ; Height + VarSetCapacity(BitmapData, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + NumPut( 4 * width, BitmapData, 8, "int") ; Stride + NumPut( pBits, BitmapData, 16, "ptr") ; Scan0 + + ; Use LockBits to create a writable buffer that converts pARGB to ARGB. + DllCall("gdiplus\GdipBitmapLockBits" + , "ptr", pBitmap + , "ptr", &Rect + , "uint", 6 ; ImageLockMode.UserInputBuffer | ImageLockMode.WriteOnly + , "int", 0xE200B ; Format32bppPArgb + , "ptr", &BitmapData) ; Contains the pointer (pBits) to the hbm. + + ; Copies the image (hBitmap) to a top-down bitmap. Removes bottom-up-ness if present. + DllCall("gdi32\BitBlt" + , "ptr", hdc, "int", 0, "int", 0, "int", width, "int", height + , "ptr", image, "int", 0, "int", 0, "uint", 0x00CC0020) ; SRCCOPY + + ; Convert the pARGB pixels copied into the device independent bitmap (hbm) to ARGB. + DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", &BitmapData) + + ; Cleanup the hBitmap and device contexts. + DllCall("SelectObject", "ptr", hdc, "ptr", obm) + DllCall("DeleteObject", "ptr", hbm) + DllCall("DeleteDC", "ptr", hdc) + + return pBitmap } from_hBitmap(image) { @@ -2258,7 +2322,7 @@ class ImagePut { ; Create a filepath based on the timestamp. if (filename == "") { - FormatTime, filename,, % "yyyy-MM-dd HH?mm?ss" + FormatTime, filename,, % "yyyy-MM-dd HH꞉mm꞉ss" filepath := directory "\" filename "." extension while FileExist(filepath) ; Check for collisions. filepath := directory "\" filename " (" A_Index ")." extension diff --git a/ImagePut.ahk b/ImagePut.ahk index 920d64f2..9c851ed8 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1225,9 +1225,73 @@ class ImagePut { } static from_dc(image) { - if !(hbm := DllCall("GetCurrentObject", "ptr", image, "uint", 7)) + ; An application cannot select a single bitmap into more than one DC at a time. + if !(sbm := DllCall("GetCurrentObject", "ptr", image, "uint", 7)) throw Error("The device context has no bitmap selected.") - return this.from_hBitmap(hbm) + + ; struct DIBSECTION - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-dibsection + ; struct BITMAP - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmap + dib := Buffer(64+5*A_PtrSize) ; sizeof(DIBSECTION) = 84, 104 + DllCall("GetObject", "ptr", sbm, "int", dib.size, "ptr", dib) + , width := NumGet(dib, 4, "uint") + , height := NumGet(dib, 8, "uint") + , bpp := NumGet(dib, 18, "ushort") + , pBits := NumGet(dib, A_PtrSize = 4 ? 20:24, "ptr") + + ; Fallback to built-in method if pixels are not 32-bit ARGB or hBitmap is a device dependent bitmap. + if (pBits = 0 || bpp != 32) { ; This built-in version is 120% faster but ignores transparency. + DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "ptr", sbm, "ptr", 0, "ptr*", &pBitmap:=0) + return pBitmap + } + + ; Create a device independent bitmap with negative height. All DIBs use the screen pixel format (pARGB). + ; Use hbm to buffer the image such that top-down and bottom-up images are mapped to this top-down buffer. + ; pBits is the pointer to (top-down) pixel values. The Scan0 will point to the pBits. + ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader + hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") + bi := Buffer(40, 0) ; sizeof(bi) = 40 + NumPut( "uint", 40, bi, 0) ; Size + NumPut( "int", width, bi, 4) ; Width + NumPut( "int", -height, bi, 8) ; Height - Negative so (0, 0) is top-left. + NumPut("ushort", 1, bi, 12) ; Planes + NumPut("ushort", 32, bi, 14) ; BitCount / BitsPerPixel + hbm := DllCall("CreateDIBSection", "ptr", hdc, "ptr", bi, "uint", 0, "ptr*", &pBits:=0, "ptr", 0, "uint", 0, "ptr") + obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") + + ; This is the 32-bit ARGB pBitmap (different from an hBitmap) that will receive the final converted pixels. + DllCall("gdiplus\GdipCreateBitmapFromScan0" + , "int", width, "int", height, "int", 0, "int", 0x26200A, "ptr", 0, "ptr*", &pBitmap:=0) + + ; Create a Scan0 buffer pointing to pBits. The buffer has pixel format pARGB. + Rect := Buffer(16, 0) ; sizeof(Rect) = 16 + NumPut( "uint", width, Rect, 8) ; Width + NumPut( "uint", height, Rect, 12) ; Height + BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + NumPut( "int", 4 * width, BitmapData, 8) ; Stride + NumPut( "ptr", pBits, BitmapData, 16) ; Scan0 + + ; Use LockBits to create a writable buffer that converts pARGB to ARGB. + DllCall("gdiplus\GdipBitmapLockBits" + , "ptr", pBitmap + , "ptr", Rect + , "uint", 6 ; ImageLockMode.UserInputBuffer | ImageLockMode.WriteOnly + , "int", 0xE200B ; Format32bppPArgb + , "ptr", BitmapData) ; Contains the pointer (pBits) to the hbm. + + ; Copies the image (hBitmap) to a top-down bitmap. Removes bottom-up-ness if present. + DllCall("gdi32\BitBlt" + , "ptr", hdc, "int", 0, "int", 0, "int", width, "int", height + , "ptr", image, "int", 0, "int", 0, "uint", 0x00CC0020) ; SRCCOPY + + ; Convert the pARGB pixels copied into the device independent bitmap (hbm) to ARGB. + DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", BitmapData) + + ; Cleanup the hBitmap and device contexts. + DllCall("SelectObject", "ptr", hdc, "ptr", obm) + DllCall("DeleteObject", "ptr", hbm) + DllCall("DeleteDC", "ptr", hdc) + + return pBitmap } static from_hBitmap(image) { @@ -2258,7 +2322,7 @@ class ImagePut { ; Create a filepath based on the timestamp. if (filename == "") { - filename := FormatTime(, "yyyy-MM-dd HH?mm?ss") + filename := FormatTime(, "yyyy-MM-dd HH꞉mm꞉ss") filepath := directory "\" filename "." extension while FileExist(filepath) ; Check for collisions. filepath := directory "\" filename " (" A_Index ")." extension From 0bcc5f7de9feb0a1969117e4a00dd95e145a0373 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 26 Jan 2022 19:02:16 -0500 Subject: [PATCH 163/492] Error message when bitmap is already selected onto a DC --- ImagePut (for v1).ahk | 3 +++ ImagePut.ahk | 3 +++ 2 files changed, 6 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 4e982b93..a4920d2f 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1314,6 +1314,9 @@ class ImagePut { sdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") ; Creates a memory DC compatible with the current screen. obm := DllCall("SelectObject", "ptr", sdc, "ptr", image, "ptr") ; Put the (hBitmap) image onto the device context. + if (obm == 0) + throw Exception("The bitmap is already selected onto a device context.") + ; Create a device independent bitmap with negative height. All DIBs use the screen pixel format (pARGB). ; Use hbm to buffer the image such that top-down and bottom-up images are mapped to this top-down buffer. ; pBits is the pointer to (top-down) pixel values. The Scan0 will point to the pBits. diff --git a/ImagePut.ahk b/ImagePut.ahk index 9c851ed8..1f26d332 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1314,6 +1314,9 @@ class ImagePut { sdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") ; Creates a memory DC compatible with the current screen. obm := DllCall("SelectObject", "ptr", sdc, "ptr", image, "ptr") ; Put the (hBitmap) image onto the device context. + if (obm == 0) + throw Exception("The bitmap is already selected onto a device context.") + ; Create a device independent bitmap with negative height. All DIBs use the screen pixel format (pARGB). ; Use hbm to buffer the image such that top-down and bottom-up images are mapped to this top-down buffer. ; pBits is the pointer to (top-down) pixel values. The Scan0 will point to the pBits. From ae9a3f9c081582af13bd5230cf321ab28a85a891 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 26 Jan 2022 19:26:31 -0500 Subject: [PATCH 164/492] ImageDestroy properly disposes of the HBITMAP in the DC --- ImagePut (for v1).ahk | 3 +++ ImagePut.ahk | 3 +++ 2 files changed, 6 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index a4920d2f..09670aee 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2432,6 +2432,9 @@ class ImageDestroy extends ImagePut { } if (DllCall("GetObjectType", "ptr", image, "uint") == 10) { ; OBJ_MEMDC + obm := DllCall("CreateBitmap", "int", 0, "int", 0, "uint", 1, "uint", 1, "ptr", 0, "ptr") + hbm := DllCall("SelectObject", "ptr", image, "ptr", obm, "ptr") + DllCall("DeleteObject", "ptr", hbm) DllCall("DeleteDC", "ptr", image) } } diff --git a/ImagePut.ahk b/ImagePut.ahk index 1f26d332..81eb5b38 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2432,6 +2432,9 @@ class ImageDestroy extends ImagePut { } if (DllCall("GetObjectType", "ptr", image, "uint") == 10) { ; OBJ_MEMDC + obm := DllCall("CreateBitmap", "int", 0, "int", 0, "uint", 1, "uint", 1, "ptr", 0, "ptr") + hbm := DllCall("SelectObject", "ptr", image, "ptr", obm, "ptr") + DllCall("DeleteObject", "ptr", hbm) DllCall("DeleteDC", "ptr", image) } } From af60765d04ce87c18a1c1eb79bd2ced34a0ac9df Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 31 Jan 2022 21:34:32 -0500 Subject: [PATCH 165/492] InageShow centering image now DPI aware --- ImagePut (for v1).ahk | 28 ++++++++++++++++++++-------- ImagePut.ahk | 30 +++++++++++++++++++++--------- 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 09670aee..bd361e1f 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1666,17 +1666,23 @@ class ImagePut { DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) + ; Get Screen width and height with DPI awareness. + dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -4, "ptr") + ScreenWidth := A_ScreenWidth + ScreenHeight := A_ScreenHeight + DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") + ; If both dimensions exceed the screen boundaries, compare the aspect ratio of the image ; to the aspect ratio of the screen to determine the scale factor. Default scale is 1. - s := (width > A_ScreenWidth) && (width / height > A_ScreenWidth / A_ScreenHeight) ? A_ScreenWidth / width - : (height > A_ScreenHeight) && (width / height <= A_ScreenWidth / A_ScreenHeight) ? A_ScreenHeight / height + s := (width > ScreenWidth) && (width / height > ScreenWidth / ScreenHeight) ? ScreenWidth / width + : (height > ScreenHeight) && (width / height <= ScreenWidth / ScreenHeight) ? ScreenHeight / height : 1 w := IsObject(pos) && pos.HasKey(3) ? pos[3] : s * width h := IsObject(pos) && pos.HasKey(4) ? pos[4] : s * height - x := IsObject(pos) && pos.HasKey(1) ? pos[1] : 0.5*(A_ScreenWidth - w) - y := IsObject(pos) && pos.HasKey(2) ? pos[2] : 0.5*(A_ScreenHeight - h) + x := IsObject(pos) && pos.HasKey(1) ? pos[1] : 0.5*(ScreenWidth - w) + y := IsObject(pos) && pos.HasKey(2) ? pos[2] : 0.5*(ScreenHeight - h) ; Resolve dependent coordinates first, coordinates second, and distances last. x2 := Round(x + w) @@ -1740,17 +1746,23 @@ class ImagePut { DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) + ; Get Screen width and height with DPI awareness. + dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -4, "ptr") + ScreenWidth := A_ScreenWidth + ScreenHeight := A_ScreenHeight + DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") + ; If both dimensions exceed the screen boundaries, compare the aspect ratio of the image ; to the aspect ratio of the screen to determine the scale factor. Default scale is 1. - s := (width > A_ScreenWidth) && (width / height > A_ScreenWidth / A_ScreenHeight) ? A_ScreenWidth / width - : (height > A_ScreenHeight) && (width / height <= A_ScreenWidth / A_ScreenHeight) ? A_ScreenHeight / height + s := (width > ScreenWidth) && (width / height > ScreenWidth / ScreenHeight) ? ScreenWidth / width + : (height > ScreenHeight) && (width / height <= ScreenWidth / ScreenHeight) ? ScreenHeight / height : 1 w := IsObject(pos) && pos.HasKey(3) ? pos[3] : s * width h := IsObject(pos) && pos.HasKey(4) ? pos[4] : s * height - x := IsObject(pos) && pos.HasKey(1) ? pos[1] : 0.5*(A_ScreenWidth - w) - y := IsObject(pos) && pos.HasKey(2) ? pos[2] : 0.5*(A_ScreenHeight - h) + x := IsObject(pos) && pos.HasKey(1) ? pos[1] : 0.5*(ScreenWidth - w) + y := IsObject(pos) && pos.HasKey(2) ? pos[2] : 0.5*(ScreenHeight - h) ; Resolve dependent coordinates first, coordinates second, and distances last. x2 := Round(x + w) diff --git a/ImagePut.ahk b/ImagePut.ahk index 81eb5b38..8828abef 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1315,7 +1315,7 @@ class ImagePut { obm := DllCall("SelectObject", "ptr", sdc, "ptr", image, "ptr") ; Put the (hBitmap) image onto the device context. if (obm == 0) - throw Exception("The bitmap is already selected onto a device context.") + throw Error("The bitmap is already selected onto a device context.") ; Create a device independent bitmap with negative height. All DIBs use the screen pixel format (pARGB). ; Use hbm to buffer the image such that top-down and bottom-up images are mapped to this top-down buffer. @@ -1666,17 +1666,23 @@ class ImagePut { DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) + ; Get Screen width and height with DPI awareness. + dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -4, "ptr") + ScreenWidth := A_ScreenWidth + ScreenHeight := A_ScreenHeight + DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") + ; If both dimensions exceed the screen boundaries, compare the aspect ratio of the image ; to the aspect ratio of the screen to determine the scale factor. Default scale is 1. - s := (width > A_ScreenWidth) && (width / height > A_ScreenWidth / A_ScreenHeight) ? A_ScreenWidth / width - : (height > A_ScreenHeight) && (width / height <= A_ScreenWidth / A_ScreenHeight) ? A_ScreenHeight / height + s := (width > ScreenWidth) && (width / height > ScreenWidth / ScreenHeight) ? ScreenWidth / width + : (height > ScreenHeight) && (width / height <= ScreenWidth / ScreenHeight) ? ScreenHeight / height : 1 w := IsObject(pos) && pos.Has(3) ? pos[3] : s * width h := IsObject(pos) && pos.Has(4) ? pos[4] : s * height - x := IsObject(pos) && pos.Has(1) ? pos[1] : 0.5*(A_ScreenWidth - w) - y := IsObject(pos) && pos.Has(2) ? pos[2] : 0.5*(A_ScreenHeight - h) + x := IsObject(pos) && pos.Has(1) ? pos[1] : 0.5*(ScreenWidth - w) + y := IsObject(pos) && pos.Has(2) ? pos[2] : 0.5*(ScreenHeight - h) ; Resolve dependent coordinates first, coordinates second, and distances last. x2 := Round(x + w) @@ -1740,17 +1746,23 @@ class ImagePut { DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) + ; Get Screen width and height with DPI awareness. + dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -4, "ptr") + ScreenWidth := A_ScreenWidth + ScreenHeight := A_ScreenHeight + DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") + ; If both dimensions exceed the screen boundaries, compare the aspect ratio of the image ; to the aspect ratio of the screen to determine the scale factor. Default scale is 1. - s := (width > A_ScreenWidth) && (width / height > A_ScreenWidth / A_ScreenHeight) ? A_ScreenWidth / width - : (height > A_ScreenHeight) && (width / height <= A_ScreenWidth / A_ScreenHeight) ? A_ScreenHeight / height + s := (width > ScreenWidth) && (width / height > ScreenWidth / ScreenHeight) ? ScreenWidth / width + : (height > ScreenHeight) && (width / height <= ScreenWidth / ScreenHeight) ? ScreenHeight / height : 1 w := IsObject(pos) && pos.Has(3) ? pos[3] : s * width h := IsObject(pos) && pos.Has(4) ? pos[4] : s * height - x := IsObject(pos) && pos.Has(1) ? pos[1] : 0.5*(A_ScreenWidth - w) - y := IsObject(pos) && pos.Has(2) ? pos[2] : 0.5*(A_ScreenHeight - h) + x := IsObject(pos) && pos.Has(1) ? pos[1] : 0.5*(ScreenWidth - w) + y := IsObject(pos) && pos.Has(2) ? pos[2] : 0.5*(ScreenHeight - h) ; Resolve dependent coordinates first, coordinates second, and distances last. x2 := Round(x + w) From ad1dd8d7a7a8bac8e23118343a78c97aa4efcda2 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 31 Jan 2022 22:05:57 -0500 Subject: [PATCH 166/492] Disable auto scaling when DPI changes --- ImagePut (for v1).ahk | 4 ++++ ImagePut.ahk | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index bd361e1f..ff73661a 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1700,6 +1700,7 @@ class ImagePut { DllCall("AdjustWindowRectEx", "ptr", &rect, "uint", style, "uint", 0, "uint", styleEx) + dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") hwnd := DllCall("CreateWindowEx" , "uint", styleEx , "str", this.WindowClass() ; lpClassName @@ -1714,6 +1715,7 @@ class ImagePut { , "ptr", 0 ; hInstance , "ptr", 0 ; lpParam , "ptr") + DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") ; Tests have shown that changing the system default colors has no effect on F0F0F0. ; Must call SetWindowLong with WS_EX_LAYERED immediately before SetLayeredWindowAttributes. @@ -1832,6 +1834,7 @@ class ImagePut { DllCall("gdiplus\GdipDeleteGraphics", "ptr", pGraphics) } + dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") hwnd := DllCall("CreateWindowEx" , "uint", styleEx | WS_EX_LAYERED ; dwExStyle , "str", this.WindowClass() ; lpClassName @@ -1846,6 +1849,7 @@ class ImagePut { , "ptr", 0 ; hInstance , "ptr", 0 ; lpParam , "ptr") + DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") ; Draw the contents of the device context onto the layered window. DllCall("UpdateLayeredWindow" diff --git a/ImagePut.ahk b/ImagePut.ahk index 8828abef..a763a216 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1700,6 +1700,7 @@ class ImagePut { DllCall("AdjustWindowRectEx", "ptr", rect, "uint", style, "uint", 0, "uint", styleEx) + dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") hwnd := DllCall("CreateWindowEx" , "uint", styleEx , "str", this.WindowClass() ; lpClassName @@ -1714,6 +1715,7 @@ class ImagePut { , "ptr", 0 ; hInstance , "ptr", 0 ; lpParam , "ptr") + DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") ; Tests have shown that changing the system default colors has no effect on F0F0F0. ; Must call SetWindowLong with WS_EX_LAYERED immediately before SetLayeredWindowAttributes. @@ -1832,6 +1834,7 @@ class ImagePut { DllCall("gdiplus\GdipDeleteGraphics", "ptr", pGraphics) } + dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") hwnd := DllCall("CreateWindowEx" , "uint", styleEx | WS_EX_LAYERED ; dwExStyle , "str", this.WindowClass() ; lpClassName @@ -1846,6 +1849,7 @@ class ImagePut { , "ptr", 0 ; hInstance , "ptr", 0 ; lpParam , "ptr") + DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") ; Draw the contents of the device context onto the layered window. DllCall("UpdateLayeredWindow" From 03a82dc009ec6896a7ae518006c7b2dcf84d4c2c Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 31 Jan 2022 22:31:45 -0500 Subject: [PATCH 167/492] from_screen and from_wallpaper are now DPI aware --- ImagePut (for v1).ahk | 6 +++++- ImagePut.ahk | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index ff73661a..3a3b4ea4 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -988,8 +988,10 @@ class ImagePut { from_wallpaper() { ; Get the width and height of all monitors. + dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") width := DllCall("GetSystemMetrics", "int", 78, "int") height := DllCall("GetSystemMetrics", "int", 79, "int") + DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") @@ -1209,8 +1211,9 @@ class ImagePut { } from_monitor(image) { + dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") if (image > 0) { - SysGet _, Monitor, image + SysGet _, Monitor, % image x := _Left y := _Top w := _Right - _Left @@ -1221,6 +1224,7 @@ class ImagePut { w := DllCall("GetSystemMetrics", "int", 78, "int") h := DllCall("GetSystemMetrics", "int", 79, "int") } + DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") return this.from_screenshot([x,y,w,h]) } diff --git a/ImagePut.ahk b/ImagePut.ahk index a763a216..2afc6853 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -988,8 +988,10 @@ class ImagePut { static from_wallpaper() { ; Get the width and height of all monitors. + dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") width := DllCall("GetSystemMetrics", "int", 78, "int") height := DllCall("GetSystemMetrics", "int", 79, "int") + DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") @@ -1209,6 +1211,7 @@ class ImagePut { } static from_monitor(image) { + dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") if (image > 0) { MonitorGet(image, &Left, &Top, &Right, &Bottom) x := Left @@ -1221,6 +1224,7 @@ class ImagePut { w := DllCall("GetSystemMetrics", "int", 78, "int") h := DllCall("GetSystemMetrics", "int", 79, "int") } + DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") return this.from_screenshot([x,y,w,h]) } From c9b203c3e9689e36a5f4804020527e111fa2fdaf Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 31 Jan 2022 22:37:25 -0500 Subject: [PATCH 168/492] from_window can now capture windows with different DPI --- ImagePut (for v1).ahk | 2 ++ ImagePut.ahk | 2 ++ 2 files changed, 4 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 3a3b4ea4..2b101e07 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -904,9 +904,11 @@ class ImagePut { DllCall("ShowWindow", "ptr", image, "int", 4) ; Get the width and height of the client window. + dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") DllCall("GetClientRect", "ptr", image, "ptr", &Rect := VarSetCapacity(Rect, 16)) ; sizeof(RECT) = 16 , width := NumGet(Rect, 8, "int") , height := NumGet(Rect, 12, "int") + DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") diff --git a/ImagePut.ahk b/ImagePut.ahk index 2afc6853..a6a83f88 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -904,9 +904,11 @@ class ImagePut { DllCall("ShowWindow", "ptr", image, "int", 4) ; Get the width and height of the client window. + dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") DllCall("GetClientRect", "ptr", image, "ptr", Rect := Buffer(16)) ; sizeof(RECT) = 16 , width := NumGet(Rect, 8, "int") , height := NumGet(Rect, 12, "int") + DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") From 4b7db4b6dc0196015adaec804ac05c4cb3854ffa Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 31 Jan 2022 22:53:29 -0500 Subject: [PATCH 169/492] from_desktop is now DPI aware --- ImagePut (for v1).ahk | 2 ++ ImagePut.ahk | 2 ++ 2 files changed, 4 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 2b101e07..83dd72a5 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -951,9 +951,11 @@ class ImagePut { throw Exception("Could not locate hidden window behind desktop.") ; Get the width and height of the client window. + dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") DllCall("GetClientRect", "ptr", WorkerW, "ptr", &Rect := VarSetCapacity(Rect, 16)) ; sizeof(RECT) = 16 , width := NumGet(Rect, 8, "int") , height := NumGet(Rect, 12, "int") + DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") ; Get device context of spawned window. sdc := DllCall("GetDCEx", "ptr", WorkerW, "ptr", 0, "int", 0x403, "ptr") ; LockWindowUpdate | Cache | Window diff --git a/ImagePut.ahk b/ImagePut.ahk index a6a83f88..41018ab1 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -951,9 +951,11 @@ class ImagePut { throw Error("Could not locate hidden window behind desktop.") ; Get the width and height of the client window. + dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") DllCall("GetClientRect", "ptr", WorkerW, "ptr", Rect := Buffer(16)) ; sizeof(RECT) = 16 , width := NumGet(Rect, 8, "int") , height := NumGet(Rect, 12, "int") + DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") ; Get device context of spawned window. sdc := DllCall("GetDCEx", "ptr", WorkerW, "ptr", 0, "int", 0x403, "ptr") ; LockWindowUpdate | Cache | Window From 9c8ed1269d9e03a1c377fc8b7a9e2b69cb9648a9 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 1 Feb 2022 12:04:31 -0500 Subject: [PATCH 170/492] Correctly set default window styles if null --- ImagePut (for v1).ahk | 8 ++++++++ ImagePut.ahk | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 83dd72a5..0518b9b3 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1670,6 +1670,10 @@ class ImagePut { WS_VISIBLE := 0x10000000 ; Show on creation. WS_EX_LAYERED := 0x80000 ; For UpdateLayeredWindow. + ; Set default styles if null. + style := (style == "") ? WS_POPUP | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU : style + styleEx := (styleEx == "") ? WS_EX_TOPMOST | WS_EX_DLGMODALFRAME : styleEx + ; Get Bitmap width and height. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) @@ -1748,6 +1752,10 @@ class ImagePut { WS_EX_TOOLWINDOW := 0x80 ; Hides from Alt+Tab menu. Removes small icon. WS_EX_LAYERED := 0x80000 ; For UpdateLayeredWindow. + ; Set default styles if null. + style := (style == "") ? WS_POPUP | WS_VISIBLE : style + styleEx := (styleEx == "") ? WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_EX_LAYERED : styleEx + ; Prevent the script from exiting early. void := ObjBindMethod({}, {}) Hotkey % "^+F12", % void, On diff --git a/ImagePut.ahk b/ImagePut.ahk index 41018ab1..a2eda9d3 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1670,6 +1670,10 @@ class ImagePut { WS_VISIBLE := 0x10000000 ; Show on creation. WS_EX_LAYERED := 0x80000 ; For UpdateLayeredWindow. + ; Set default styles if null. + style := (style == "") ? WS_POPUP | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU : style + styleEx := (styleEx == "") ? WS_EX_TOPMOST | WS_EX_DLGMODALFRAME : styleEx + ; Get Bitmap width and height. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) @@ -1748,6 +1752,10 @@ class ImagePut { WS_EX_TOOLWINDOW := 0x80 ; Hides from Alt+Tab menu. Removes small icon. WS_EX_LAYERED := 0x80000 ; For UpdateLayeredWindow. + ; Set default styles if null. + style := (style == "") ? WS_POPUP | WS_VISIBLE : style + styleEx := (styleEx == "") ? WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_EX_LAYERED : styleEx + ; Prevent the script from exiting early. Persistent(true) From fb2ffaa3866079a460ba8c2cadb149be2bbc5bd0 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 1 Feb 2022 14:22:00 -0500 Subject: [PATCH 171/492] Read hBitmaps even when selected onto a device context --- ImagePut (for v1).ahk | 30 ++++++++++++++++-------------- ImagePut.ahk | 28 ++++++++++++++++------------ 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 0518b9b3..ddbf314e 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1318,13 +1318,6 @@ class ImagePut { return pBitmap } - ; Create a handle to a device context and associate the image. - sdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") ; Creates a memory DC compatible with the current screen. - obm := DllCall("SelectObject", "ptr", sdc, "ptr", image, "ptr") ; Put the (hBitmap) image onto the device context. - - if (obm == 0) - throw Exception("The bitmap is already selected onto a device context.") - ; Create a device independent bitmap with negative height. All DIBs use the screen pixel format (pARGB). ; Use hbm to buffer the image such that top-down and bottom-up images are mapped to this top-down buffer. ; pBits is the pointer to (top-down) pixel values. The Scan0 will point to the pBits. @@ -1351,7 +1344,7 @@ class ImagePut { NumPut( 4 * width, BitmapData, 8, "int") ; Stride NumPut( pBits, BitmapData, 16, "ptr") ; Scan0 - ; Use LockBits to create a writable buffer that converts pARGB to ARGB. + ; Use LockBits to create a copy-from buffer on pBits that converts pARGB to ARGB. DllCall("gdiplus\GdipBitmapLockBits" , "ptr", pBitmap , "ptr", &Rect @@ -1359,20 +1352,29 @@ class ImagePut { , "int", 0xE200B ; Format32bppPArgb , "ptr", &BitmapData) ; Contains the pointer (pBits) to the hbm. + ; If the source image cannot be selected onto a device context BitBlt cannot be used. + sdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") ; Creates a memory DC compatible with the current screen. + old := DllCall("SelectObject", "ptr", sdc, "ptr", image, "ptr") ; Returns 0 on failure. + ; Copies the image (hBitmap) to a top-down bitmap. Removes bottom-up-ness if present. - DllCall("gdi32\BitBlt" - , "ptr", hdc, "int", 0, "int", 0, "int", width, "int", height - , "ptr", sdc, "int", 0, "int", 0, "uint", 0x00CC0020) ; SRCCOPY + if (old) ; Using BitBlt is about 10% faster than GetDIBits. + DllCall("gdi32\BitBlt" + , "ptr", hdc, "int", 0, "int", 0, "int", width, "int", height + , "ptr", sdc, "int", 0, "int", 0, "uint", 0x00CC0020) ; SRCCOPY + else + DllCall("GetDIBits", "ptr", hdc, "ptr", image, "uint", 0, "uint", height, "ptr", pBits, "ptr", &bi, "uint", 0) + + ; The stock bitmap (obm) can never be leaked. + DllCall("SelectObject", "ptr", sdc, "ptr", obm) + DllCall("DeleteDC", "ptr", sdc) - ; Convert the pARGB pixels copied into the device independent bitmap (hbm) to ARGB. + ; Write the pARGB pixels from the device independent bitmap (hbm) to the ARGB pBitmap. DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", &BitmapData) ; Cleanup the hBitmap and device contexts. DllCall("SelectObject", "ptr", hdc, "ptr", obm) DllCall("DeleteObject", "ptr", hbm) DllCall("DeleteDC", "ptr", hdc) - DllCall("SelectObject", "ptr", sdc, "ptr", obm) - DllCall("DeleteDC", "ptr", sdc) return pBitmap } diff --git a/ImagePut.ahk b/ImagePut.ahk index a2eda9d3..07ce5752 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1318,13 +1318,6 @@ class ImagePut { return pBitmap } - ; Create a handle to a device context and associate the image. - sdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") ; Creates a memory DC compatible with the current screen. - obm := DllCall("SelectObject", "ptr", sdc, "ptr", image, "ptr") ; Put the (hBitmap) image onto the device context. - - if (obm == 0) - throw Error("The bitmap is already selected onto a device context.") - ; Create a device independent bitmap with negative height. All DIBs use the screen pixel format (pARGB). ; Use hbm to buffer the image such that top-down and bottom-up images are mapped to this top-down buffer. ; pBits is the pointer to (top-down) pixel values. The Scan0 will point to the pBits. @@ -1351,7 +1344,7 @@ class ImagePut { NumPut( "int", 4 * width, BitmapData, 8) ; Stride NumPut( "ptr", pBits, BitmapData, 16) ; Scan0 - ; Use LockBits to create a writable buffer that converts pARGB to ARGB. + ; Use LockBits to create a copy-from buffer on pBits that converts pARGB to ARGB. DllCall("gdiplus\GdipBitmapLockBits" , "ptr", pBitmap , "ptr", Rect @@ -1359,12 +1352,23 @@ class ImagePut { , "int", 0xE200B ; Format32bppPArgb , "ptr", BitmapData) ; Contains the pointer (pBits) to the hbm. + ; If the source image cannot be selected onto a device context BitBlt cannot be used. + sdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") ; Creates a memory DC compatible with the current screen. + old := DllCall("SelectObject", "ptr", sdc, "ptr", image, "ptr") ; Returns 0 on failure. + ; Copies the image (hBitmap) to a top-down bitmap. Removes bottom-up-ness if present. - DllCall("gdi32\BitBlt" - , "ptr", hdc, "int", 0, "int", 0, "int", width, "int", height - , "ptr", sdc, "int", 0, "int", 0, "uint", 0x00CC0020) ; SRCCOPY + if (old) ; Using BitBlt is about 10% faster than GetDIBits. + DllCall("gdi32\BitBlt" + , "ptr", hdc, "int", 0, "int", 0, "int", width, "int", height + , "ptr", sdc, "int", 0, "int", 0, "uint", 0x00CC0020) ; SRCCOPY + else + DllCall("GetDIBits", "ptr", hdc, "ptr", image, "uint", 0, "uint", height, "ptr", pBits, "ptr", bi, "uint", 0) + + ; The stock bitmap (obm) can never be leaked. + DllCall("SelectObject", "ptr", sdc, "ptr", obm) + DllCall("DeleteDC", "ptr", sdc) - ; Convert the pARGB pixels copied into the device independent bitmap (hbm) to ARGB. + ; Write the pARGB pixels from the device independent bitmap (hbm) to the ARGB pBitmap. DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", BitmapData) ; Cleanup the hBitmap and device contexts. From 06b850fe41eb7ff19d6e78189286c43269ea6abb Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 1 Feb 2022 14:24:27 -0500 Subject: [PATCH 172/492] Add comment about GdipCreateHBITMAPFromBitmap preserving transparency --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index ddbf314e..913f1c8b 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2164,7 +2164,7 @@ class ImagePut { put_hBitmap(pBitmap, alpha := "") { ; Revert to built in functionality if a replacement color is declared. - if (alpha != "") { ; This built-in version is about 25% slower. + if (alpha != "") { ; This built-in version is about 25% slower and also preserves transparency. DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", "ptr", pBitmap, "ptr*", hbm:=0, "uint", alpha) return hbm } diff --git a/ImagePut.ahk b/ImagePut.ahk index 07ce5752..d9dc4530 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2166,7 +2166,7 @@ class ImagePut { static put_hBitmap(pBitmap, alpha := "") { ; Revert to built in functionality if a replacement color is declared. - if (alpha != "") { ; This built-in version is about 25% slower. + if (alpha != "") { ; This built-in version is about 25% slower and also preserves transparency. DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", "ptr", pBitmap, "ptr*", &hbm:=0, "uint", alpha) return hbm } From ba487df34deb2a5ec6d91de2e798274503bb7fee Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 1 Feb 2022 14:29:34 -0500 Subject: [PATCH 173/492] v1.6.0 --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 913f1c8b..9b1cdb78 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -3,7 +3,7 @@ ; Author: Edison Hua (iseahound) ; Github: https://github.com/iseahound/ImagePut ; Date: 2022-01-01 -; Version: 1.5.1 +; Version: 1.6.0 #Requires AutoHotkey v1.1.33+ diff --git a/ImagePut.ahk b/ImagePut.ahk index d9dc4530..134c63a4 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -3,7 +3,7 @@ ; Author: Edison Hua (iseahound) ; Github: https://github.com/iseahound/ImagePut ; Date: 2022-01-01 -; Version: 1.5.1 +; Version: 1.6.0 #Requires AutoHotkey v2.0-beta.3+ From 09388576f13f95efa8107d3cdebc699992c2b0e7 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 4 Feb 2022 00:14:18 -0500 Subject: [PATCH 174/492] Re-add Byte Order Mark --- ImagePut (for v1).ahk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 9b1cdb78..4e2019d6 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2359,7 +2359,7 @@ class ImagePut { ; Create a filepath based on the timestamp. if (filename == "") { - FormatTime, filename,, % "yyyy-MM-dd HH꞉mm꞉ss" + FormatTime, filename,, % "yyyy-MM-dd HH?mm?ss" filepath := directory "\" filename "." extension while FileExist(filepath) ; Check for collisions. filepath := directory "\" filename " (" A_Index ")." extension From 11c66f72105837d07b8606e928f1f9a9d9ed45af Mon Sep 17 00:00:00 2001 From: Animan8000 <30600651+Animan8000@users.noreply.github.com> Date: Tue, 8 Feb 2022 17:00:17 +0100 Subject: [PATCH 175/492] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7d5ba027..96e59b7f 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ If you like this and want to see my other AutoHotkey libraries: ## So you want to convert an image? -But you don't how. That's okay because you can just do this: +But you don't know how. That's okay because you can just do this: str := ImagePutBase64("cats.jpg") From 06625d7ad8b0816a65bb0d6d8b7b393fdbe0fa66 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 13 Feb 2022 16:45:28 -0500 Subject: [PATCH 176/492] Re-align files --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 4e2019d6..9b1cdb78 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2359,7 +2359,7 @@ class ImagePut { ; Create a filepath based on the timestamp. if (filename == "") { - FormatTime, filename,, % "yyyy-MM-dd HH?mm?ss" + FormatTime, filename,, % "yyyy-MM-dd HH꞉mm꞉ss" filepath := directory "\" filename "." extension while FileExist(filepath) ; Check for collisions. filepath := directory "\" filename " (" A_Index ")." extension diff --git a/ImagePut.ahk b/ImagePut.ahk index 134c63a4..a490dd53 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1375,8 +1375,6 @@ class ImagePut { DllCall("SelectObject", "ptr", hdc, "ptr", obm) DllCall("DeleteObject", "ptr", hbm) DllCall("DeleteDC", "ptr", hdc) - DllCall("SelectObject", "ptr", sdc, "ptr", obm) - DllCall("DeleteDC", "ptr", sdc) return pBitmap } From 01c374d32756cf070bdb3739c04192f68f8f673e Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 13 Feb 2022 16:48:38 -0500 Subject: [PATCH 177/492] add comment in select_filepath --- ImagePut (for v1).ahk | 1 + ImagePut.ahk | 1 + 2 files changed, 2 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 9b1cdb78..efd91c86 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2346,6 +2346,7 @@ class ImagePut { ; An invalid extension is actually part of the filename. if !(extension ~= "^(?i:bmp|dib|rle|jpg|jpeg|jpe|jfif|gif|tif|tiff|png)$") { + ; Avoid appening an extra dot. if (extension != "") filename .= "." extension diff --git a/ImagePut.ahk b/ImagePut.ahk index a490dd53..3ceeda4c 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2346,6 +2346,7 @@ class ImagePut { ; An invalid extension is actually part of the filename. if !(extension ~= "^(?i:bmp|dib|rle|jpg|jpeg|jpe|jfif|gif|tif|tiff|png)$") { + ; Avoid appening an extra dot. if (extension != "") filename .= "." extension From 45d8133a064a2c830b001bb48abbab42512b19cb Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 13 Feb 2022 16:57:15 -0500 Subject: [PATCH 178/492] Increase file signature detection to 256 bytes --- ImagePut (for v1).ahk | 6 +++--- ImagePut.ahk | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index efd91c86..936f729d 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2281,16 +2281,16 @@ class ImagePut { select_extension(pStream, ByRef extension) { DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") - DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", &signature := VarSetCapacity(signature, 12), "uint", 12, "uint") + DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", &signature := VarSetCapacity(signature, 256), "uint", 256, "uint") - ; This function sniffs the first 12 bytes and matches a known file signature. + ; This function sniffs the first 256 bytes and matches a known file signature. ; 256 bytes is recommended, but images only need 12 bytes. ; See: https://en.wikipedia.org/wiki/List_of_file_signatures DllCall("urlmon\FindMimeFromData" , "ptr", 0 ; pBC , "ptr", 0 ; pwzUrl , "ptr", &signature ; pBuffer - , "uint", 12 ; cbSize + , "uint", 256 ; cbSize , "ptr", 0 ; pwzMimeProposed , "uint", 0x20 ; dwMimeFlags , "ptr*", MimeType:=0 ; ppwzMimeOut diff --git a/ImagePut.ahk b/ImagePut.ahk index 3ceeda4c..376f9a1c 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2281,16 +2281,16 @@ class ImagePut { static select_extension(pStream, &extension) { DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") - DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", signature := Buffer(12), "uint", 12, "HRESULT") + DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", signature := Buffer(256), "uint", 256, "HRESULT") - ; This function sniffs the first 12 bytes and matches a known file signature. + ; This function sniffs the first 256 bytes and matches a known file signature. ; 256 bytes is recommended, but images only need 12 bytes. ; See: https://en.wikipedia.org/wiki/List_of_file_signatures DllCall("urlmon\FindMimeFromData" , "ptr", 0 ; pBC , "ptr", 0 ; pwzUrl , "ptr", signature ; pBuffer - , "uint", 12 ; cbSize + , "uint", 256 ; cbSize , "ptr", 0 ; pwzMimeProposed , "uint", 0x20 ; dwMimeFlags , "ptr*", &MimeType:=0 ; ppwzMimeOut From 1f367c72e0e6079270010c572045be6c4fa0234d Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 13 Feb 2022 17:08:59 -0500 Subject: [PATCH 179/492] Always reset the stream after seeking --- ImagePut (for v1).ahk | 3 +++ ImagePut.ahk | 3 +++ 2 files changed, 6 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 936f729d..caaecfee 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2102,6 +2102,7 @@ class ImagePut { DllCall("shlwapi\IStream_Size", "ptr", pStream, "ptr*", size:=0, "uint") DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") DllCall("shlwapi\IStream_Copy", "ptr", pStream, "ptr", pFileStream, "uint", size, "uint") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") ObjRelease(pFileStream) return filepath @@ -2144,6 +2145,7 @@ class ImagePut { DllCall("shlwapi\IStream_Size", "ptr", pStream, "ptr*", size:=0, "uint") DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", &bin := VarSetCapacity(bin, size), "uint", size, "uint") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") ; Using CryptBinaryToStringA saves about 2MB in memory. DllCall("crypt32\CryptBinaryToStringA", "ptr", &bin, "uint", size, "uint", flags, "ptr", 0, "uint*", length:=0) @@ -2282,6 +2284,7 @@ class ImagePut { select_extension(pStream, ByRef extension) { DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", &signature := VarSetCapacity(signature, 256), "uint", 256, "uint") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") ; This function sniffs the first 256 bytes and matches a known file signature. ; 256 bytes is recommended, but images only need 12 bytes. diff --git a/ImagePut.ahk b/ImagePut.ahk index 376f9a1c..5cc1cee8 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2102,6 +2102,7 @@ class ImagePut { DllCall("shlwapi\IStream_Size", "ptr", pStream, "ptr*", &size:=0, "HRESULT") DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") DllCall("shlwapi\IStream_Copy", "ptr", pStream, "ptr", pFileStream, "uint", size, "HRESULT") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") ObjRelease(pFileStream) return filepath @@ -2144,6 +2145,7 @@ class ImagePut { DllCall("shlwapi\IStream_Size", "ptr", pStream, "ptr*", &size:=0, "HRESULT") DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", bin := Buffer(size), "uint", size, "HRESULT") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") ; Using CryptBinaryToStringA saves about 2MB in memory. DllCall("crypt32\CryptBinaryToStringA", "ptr", bin, "uint", size, "uint", flags, "ptr", 0, "uint*", &length:=0) @@ -2282,6 +2284,7 @@ class ImagePut { static select_extension(pStream, &extension) { DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", signature := Buffer(256), "uint", 256, "HRESULT") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") ; This function sniffs the first 256 bytes and matches a known file signature. ; 256 bytes is recommended, but images only need 12 bytes. From 04c685d2fec628883763a55d4e8523bb30817e6c Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 13 Feb 2022 17:29:15 -0500 Subject: [PATCH 180/492] SetThreadDpiAwarenessContext should be -3 --- ImagePut (for v1).ahk | 4 ++-- ImagePut.ahk | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index caaecfee..5a0d0b00 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1681,7 +1681,7 @@ class ImagePut { DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) ; Get Screen width and height with DPI awareness. - dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -4, "ptr") + dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") ScreenWidth := A_ScreenWidth ScreenHeight := A_ScreenHeight DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") @@ -1767,7 +1767,7 @@ class ImagePut { DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) ; Get Screen width and height with DPI awareness. - dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -4, "ptr") + dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") ScreenWidth := A_ScreenWidth ScreenHeight := A_ScreenHeight DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") diff --git a/ImagePut.ahk b/ImagePut.ahk index 5cc1cee8..7331ed3e 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1681,7 +1681,7 @@ class ImagePut { DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) ; Get Screen width and height with DPI awareness. - dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -4, "ptr") + dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") ScreenWidth := A_ScreenWidth ScreenHeight := A_ScreenHeight DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") @@ -1767,7 +1767,7 @@ class ImagePut { DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) ; Get Screen width and height with DPI awareness. - dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -4, "ptr") + dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") ScreenWidth := A_ScreenWidth ScreenHeight := A_ScreenHeight DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") From 78fe68d66af49af489134ba91d7b3e71e3f32c25 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 17 Feb 2022 00:15:07 -0500 Subject: [PATCH 181/492] Check window process DPI awareness --- ImagePut (for v1).ahk | 11 ++++++++++- ImagePut.ahk | 11 ++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 5a0d0b00..10bcaec1 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -903,8 +903,17 @@ class ImagePut { if DllCall("IsIconic", "ptr", image) DllCall("ShowWindow", "ptr", image, "int", 4) + ; Check window DPI awareness. + ; PROCESS_DPI_UNAWARE = 0, PROCESS_SYSTEM_DPI_AWARE = 1, PROCESS_PER_MONITOR_DPI_AWARE = 2 + DPI_AWARENESS := True ; Assume dpi aware if process cannot be opened. + DllCall("GetWindowThreadProcessId", "ptr", image, "ptr*", pid:=0, "ptr") + if hProcess := DllCall("OpenProcess", "uint", 0x0400, "int", False, "uint", pid, "ptr") { + DllCall("Shcore\GetProcessDpiAwareness", "ptr", hProcess, "int*", DPI_AWARENESS) + DllCall("CloseHandle", "ptr", hProcess) + } + ; Get the width and height of the client window. - dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") + dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", DPI_AWARENESS ? -3 : -5, "ptr") DllCall("GetClientRect", "ptr", image, "ptr", &Rect := VarSetCapacity(Rect, 16)) ; sizeof(RECT) = 16 , width := NumGet(Rect, 8, "int") , height := NumGet(Rect, 12, "int") diff --git a/ImagePut.ahk b/ImagePut.ahk index 7331ed3e..a8d0b75d 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -903,8 +903,17 @@ class ImagePut { if DllCall("IsIconic", "ptr", image) DllCall("ShowWindow", "ptr", image, "int", 4) + ; Check window DPI awareness. + ; PROCESS_DPI_UNAWARE = 0, PROCESS_SYSTEM_DPI_AWARE = 1, PROCESS_PER_MONITOR_DPI_AWARE = 2 + DPI_AWARENESS := True ; Assume dpi aware if process cannot be opened. + DllCall("GetWindowThreadProcessId", "ptr", image, "ptr*", pid:=0, "ptr") + if hProcess := DllCall("OpenProcess", "uint", 0x0400, "int", False, "uint", pid, "ptr") { + DllCall("Shcore\GetProcessDpiAwareness", "ptr", hProcess, "int*", DPI_AWARENESS) + DllCall("CloseHandle", "ptr", hProcess) + } + ; Get the width and height of the client window. - dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") + dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", DPI_AWARENESS ? -3 : -5, "ptr") DllCall("GetClientRect", "ptr", image, "ptr", Rect := Buffer(16)) ; sizeof(RECT) = 16 , width := NumGet(Rect, 8, "int") , height := NumGet(Rect, 12, "int") From 6421e78c1524fa2f7f6fa88e9c8f920dfd33b356 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 17 Feb 2022 00:18:45 -0500 Subject: [PATCH 182/492] Capitalize True and False --- ImagePut (for v1).ahk | 40 +++++++++++++++++++-------------------- ImagePut.ahk | 44 +++++++++++++++++++++---------------------- 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 10bcaec1..96d5fb35 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -134,8 +134,8 @@ ImageEqual(images*) { class ImagePut { - static decode := false ; Forces conversion using a bitmap. The original file encoding will be lost. - static validate := false ; Always copies image data into memory instead of passing references. + static decode := False ; Forces conversion using a bitmap. The original file encoding will be lost. + static validate := False ; Always copies image data into memory instead of passing references. ; ImagePut() - Puts an image from anywhere to anywhere. ; cotype - Output Type | string -> Case Insensitive. Read documentation. @@ -147,8 +147,8 @@ class ImagePut { ; Extract parameters. if IsObject(image) { - crop := ObjHasKey(image, "crop") ? image.crop : false - scale := ObjHasKey(image, "scale") ? image.scale : false + crop := ObjHasKey(image, "crop") ? image.crop : False + scale := ObjHasKey(image, "scale") ? image.scale : False decode := ObjHasKey(image, "decode") ? image.decode : this.decode validate := ObjHasKey(image, "validate") ? image.validate : this.validate @@ -159,7 +159,7 @@ class ImagePut { image := image.image } else { - crop := scale := false + crop := scale := False decode := this.decode validate := this.validate @@ -844,7 +844,7 @@ class ImagePut { ; Allow the stream to be freed while leaving the hData intact. ; Please read: https://devblogs.microsoft.com/oldnewthing/20210930-00/?p=105745 - DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", false, "ptr*", pStream:=0, "uint") + DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", False, "ptr*", pStream:=0, "uint") DllCall("CloseClipboard") return pStream } @@ -1098,7 +1098,7 @@ class ImagePut { DllCall(IPdfDocument_GetPage := NumGet(NumGet(PdfDocument+0)+6*A_PtrSize), "ptr", PdfDocument, "uint", index, "ptr*", PdfPage:=0) ; Render the page to an output stream. - DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "uint", true, "ptr*", pStreamOut:=0) + DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "uint", True, "ptr*", pStreamOut:=0) DllCall("ole32\CLSIDFromString", "wstr", "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}", "ptr", &CLSID := VarSetCapacity(CLSID, 16), "uint") DllCall("ShCore\CreateRandomAccessStreamOverStream", "ptr", pStreamOut, "uint", BSOS_DEFAULT := 0, "ptr", &CLSID, "ptr*", pRandomAccessStreamOut:=0) DllCall(IPdfPage_RenderToStreamAsync := NumGet(NumGet(PdfPage+0)+6*A_PtrSize), "ptr", PdfPage, "ptr", pRandomAccessStreamOut, "ptr*", AsyncInfo:=0) @@ -1157,7 +1157,7 @@ class ImagePut { get_url(image) { req := ComObjCreate("WinHttp.WinHttpRequest.5.1") - req.Open("GET", image, true) + req.Open("GET", image, True) req.Send() req.WaitForResponse() pStream := ComObjQuery(req.ResponseStream, "{0000000C-0000-0000-C000-000000000046}") @@ -1176,7 +1176,7 @@ class ImagePut { file.RawRead(pData+0, file.length) DllCall("GlobalUnlock", "ptr", hData) file.Close() - DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", true, "ptr*", pStream:=0, "uint") + DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", True, "ptr*", pStream:=0, "uint") return pStream } @@ -1218,7 +1218,7 @@ class ImagePut { , "ptr", &image, "uint", 0, "uint", flags, "ptr", pData, "uint*", size, "ptr", 0, "ptr", 0) DllCall("GlobalUnlock", "ptr", hData) - DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", true, "ptr*", pStream:=0, "uint") + DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", True, "ptr*", pStream:=0, "uint") return pStream } @@ -1562,7 +1562,7 @@ class ImagePut { ; Create a Stream whose underlying HGlobal must be referenced or lost forever. ; Please read: https://devblogs.microsoft.com/oldnewthing/20210929-00/?p=105742 - DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "int", false, "ptr*", pStream:=0, "uint") + DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "int", False, "ptr*", pStream:=0, "uint") this.select_codec(pBitmap, "png", "", pCodec, ep, ci, v) DllCall("gdiplus\GdipSaveImageToStream", "ptr", pBitmap, "ptr", pStream, "ptr", pCodec, "ptr", (ep) ? &ep : 0) @@ -2051,7 +2051,7 @@ class ImagePut { ; struct ICONINFO - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-iconinfo VarSetCapacity(ii, 8+3*A_PtrSize) ; sizeof(ICONINFO) = 20, 32 DllCall("GetIconInfo", "ptr", hIcon, "ptr", &ii) ; Fill the ICONINFO structure. - NumPut(false, ii, 0, "uint") ; true/false are icon/cursor respectively. + NumPut(False, ii, 0, "uint") ; True/false are icon/cursor respectively. (xHotspot != "") ? NumPut(xHotspot, ii, 4, "uint") : {} ; Set the xHotspot value. (Default: center point) (yHotspot != "") ? NumPut(yHotspot, ii, 8, "uint") : {} ; Set the yHotspot value. (Default: center point) DllCall("DestroyIcon", "ptr", hIcon) ; Destroy the icon after getting the ICONINFO structure. @@ -2104,7 +2104,7 @@ class ImagePut { , "wstr", filepath , "uint", 0x1001 ; STGM_CREATE | STGM_WRITE , "uint", 0x80 ; FILE_ATTRIBUTE_NORMAL - , "int", true ; fCreate is ignored when STGM_CREATE is set. + , "int", True ; fCreate is ignored when STGM_CREATE is set. , "ptr", 0 ; pstmTemplate (reserved) , "ptr*", pFileStream:=0 , "uint") @@ -2232,7 +2232,7 @@ class ImagePut { this.select_codec(pBitmap, extension, quality, pCodec, ep, ci, v) ; Create a Stream. - DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "int", true, "ptr*", pStream:=0, "uint") + DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "int", True, "ptr*", pStream:=0, "uint") DllCall("gdiplus\GdipSaveImageToStream", "ptr", pBitmap, "ptr", pStream, "ptr", pCodec, "ptr", (ep) ? &ep : 0) return pStream @@ -2506,7 +2506,7 @@ class ImageEqual extends ImagePut { call(images*) { ; Returns false is there are no images to be compared. if (images.length() == 0) - return false + return False this.gdiplusStartup() @@ -2555,13 +2555,13 @@ class ImageEqual extends ImagePut { Good_Ending: ; After getting isekai'ed you somehow build a prosperous kingdom and rule the land. DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap1) this.gdiplusShutdown() - return true + return True Bad_Ending: ; Turns out your best friend became super jealous of you and killed you in your sleep. DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap2) DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap1) this.gdiplusShutdown() - return false + return False } BitmapEqual(SourceBitmap1, SourceBitmap2, PixelFormat := 0x26200A) { @@ -2575,7 +2575,7 @@ class ImageEqual extends ImagePut { ; Check if source bitmap pointers are identical. if (SourceBitmap1 == SourceBitmap2) - return true + return True ; The two bitmaps must be the same size. DllCall("gdiplus\GdipGetImageWidth", "ptr", SourceBitmap1, "uint*", width1:=0) @@ -2591,7 +2591,7 @@ class ImageEqual extends ImagePut { ; Dimensions must be equal. if (width1 != width2 || height1 != height2) - return false + return False ; Create clones of the supplied source bitmaps in their original PixelFormat. ; This has the side effect of (1) removing negative stride and solves @@ -2654,6 +2654,6 @@ class ImageEqual extends ImagePut { DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap2) ; Compare stopped byte. - return (byte == size) ? true : false + return (byte == size) ? True : False } } ; End of ImageEqual class. \ No newline at end of file diff --git a/ImagePut.ahk b/ImagePut.ahk index a8d0b75d..c2769057 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -134,8 +134,8 @@ ImageEqual(images*) { class ImagePut { - static decode := false ; Forces conversion using a bitmap. The original file encoding will be lost. - static validate := false ; Always copies image data into memory instead of passing references. + static decode := False ; Forces conversion using a bitmap. The original file encoding will be lost. + static validate := False ; Always copies image data into memory instead of passing references. ; ImagePut() - Puts an image from anywhere to anywhere. ; cotype - Output Type | string -> Case Insensitive. Read documentation. @@ -147,8 +147,8 @@ class ImagePut { ; Extract parameters. if IsObject(image) { - crop := ObjHasOwnProp(image, "crop") ? image.crop : false - scale := ObjHasOwnProp(image, "scale") ? image.scale : false + crop := ObjHasOwnProp(image, "crop") ? image.crop : False + scale := ObjHasOwnProp(image, "scale") ? image.scale : False decode := ObjHasOwnProp(image, "decode") ? image.decode : this.decode validate := ObjHasOwnProp(image, "validate") ? image.validate : this.validate @@ -159,7 +159,7 @@ class ImagePut { image := image.image } else { - crop := scale := false + crop := scale := False decode := this.decode validate := this.validate @@ -844,7 +844,7 @@ class ImagePut { ; Allow the stream to be freed while leaving the hData intact. ; Please read: https://devblogs.microsoft.com/oldnewthing/20210930-00/?p=105745 - DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", false, "ptr*", &pStream:=0, "HRESULT") + DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", False, "ptr*", &pStream:=0, "HRESULT") DllCall("CloseClipboard") return pStream } @@ -1098,7 +1098,7 @@ class ImagePut { ComCall(IPdfDocument_GetPage := 6, PdfDocument, "uint", index, "ptr*", &PdfPage:=0) ; Render the page to an output stream. - DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "uint", true, "ptr*", &pStreamOut:=0) + DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "uint", True, "ptr*", &pStreamOut:=0) DllCall("ole32\CLSIDFromString", "wstr", "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}", "ptr", CLSID := Buffer(16), "HRESULT") DllCall("ShCore\CreateRandomAccessStreamOverStream", "ptr", pStreamOut, "uint", BSOS_DEFAULT := 0, "ptr", CLSID, "ptr*", &pRandomAccessStreamOut:=0) ComCall(IPdfPage_RenderToStreamAsync := 6, PdfPage, "ptr", pRandomAccessStreamOut, "ptr*", &AsyncInfo:=0) @@ -1157,7 +1157,7 @@ class ImagePut { static get_url(image) { req := ComObject("WinHttp.WinHttpRequest.5.1") - req.Open("GET", image, true) + req.Open("GET", image, True) req.Send() req.WaitForResponse() IStream := ComObjQuery(req.ResponseStream, "{0000000C-0000-0000-C000-000000000046}"), ObjAddRef(IStream.ptr) @@ -1176,7 +1176,7 @@ class ImagePut { file.RawRead(pData, file.length) DllCall("GlobalUnlock", "ptr", hData) file.Close() - DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", true, "ptr*", &pStream:=0, "HRESULT") + DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", True, "ptr*", &pStream:=0, "HRESULT") return pStream } @@ -1218,7 +1218,7 @@ class ImagePut { , "ptr", StrPtr(image), "uint", 0, "uint", flags, "ptr", pData, "uint*", size, "ptr", 0, "ptr", 0) DllCall("GlobalUnlock", "ptr", hData) - DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", true, "ptr*", &pStream:=0, "HRESULT") + DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", True, "ptr*", &pStream:=0, "HRESULT") return pStream } @@ -1562,7 +1562,7 @@ class ImagePut { ; Create a Stream whose underlying HGlobal must be referenced or lost forever. ; Please read: https://devblogs.microsoft.com/oldnewthing/20210929-00/?p=105742 - DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "int", false, "ptr*", &pStream:=0, "HRESULT") + DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "int", False, "ptr*", &pStream:=0, "HRESULT") this.select_codec(pBitmap, "png", "", &pCodec, &ep, &ci, &v) DllCall("gdiplus\GdipSaveImageToStream", "ptr", pBitmap, "ptr", pStream, "ptr", pCodec, "ptr", IsSet(ep) ? ep : 0) @@ -1768,7 +1768,7 @@ class ImagePut { styleEx := (styleEx == "") ? WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_EX_LAYERED : styleEx ; Prevent the script from exiting early. - Persistent(true) + Persistent(True) ; Get Bitmap width and height. @@ -1940,7 +1940,7 @@ class ImagePut { ; WM_DESTROY if (uMsg = 0x2) { - return Persistent(false) + return Persistent(False) } ; WM_LBUTTONDOWN @@ -2051,7 +2051,7 @@ class ImagePut { ; struct ICONINFO - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-iconinfo ii := Buffer(8+3*A_PtrSize) ; sizeof(ICONINFO) = 20, 32 DllCall("GetIconInfo", "ptr", hIcon, "ptr", ii) ; Fill the ICONINFO structure. - NumPut("uint", false, ii, 0) ; true/false are icon/cursor respectively. + NumPut("uint", False, ii, 0) ; True/False are icon/cursor respectively. (xHotspot != "") ? NumPut("uint", xHotspot, ii, 4) : {} ; Set the xHotspot value. (Default: center point) (yHotspot != "") ? NumPut("uint", yHotspot, ii, 8) : {} ; Set the yHotspot value. (Default: center point) DllCall("DestroyIcon", "ptr", hIcon) ; Destroy the icon after getting the ICONINFO structure. @@ -2104,7 +2104,7 @@ class ImagePut { , "wstr", filepath , "uint", 0x1001 ; STGM_CREATE | STGM_WRITE , "uint", 0x80 ; FILE_ATTRIBUTE_NORMAL - , "int", true ; fCreate is ignored when STGM_CREATE is set. + , "int", True ; fCreate is ignored when STGM_CREATE is set. , "ptr", 0 ; pstmTemplate (reserved) , "ptr*", &pFileStream:=0 ,"HRESULT") @@ -2232,7 +2232,7 @@ class ImagePut { this.select_codec(pBitmap, extension, quality, &pCodec, &ep, &ci, &v) ; Create a Stream. - DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "int", true, "ptr*", &pStream:=0, "HRESULT") + DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "int", True, "ptr*", &pStream:=0, "HRESULT") DllCall("gdiplus\GdipSaveImageToStream", "ptr", pBitmap, "ptr", pStream, "ptr", pCodec, "ptr", IsSet(ep) ? ep : 0) return pStream @@ -2506,7 +2506,7 @@ class ImageEqual extends ImagePut { static call(images*) { ; Returns false is there are no images to be compared. if (images.length == 0) - return false + return False this.gdiplusStartup() @@ -2555,13 +2555,13 @@ class ImageEqual extends ImagePut { Good_Ending: ; After getting isekai'ed you somehow build a prosperous kingdom and rule the land. DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap1) this.gdiplusShutdown() - return true + return True Bad_Ending: ; Turns out your best friend became super jealous of you and killed you in your sleep. DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap2) DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap1) this.gdiplusShutdown() - return false + return False } static BitmapEqual(SourceBitmap1, SourceBitmap2, PixelFormat := 0x26200A) { @@ -2575,7 +2575,7 @@ class ImageEqual extends ImagePut { ; Check if source bitmap pointers are identical. if (SourceBitmap1 == SourceBitmap2) - return true + return True ; The two bitmaps must be the same size. DllCall("gdiplus\GdipGetImageWidth", "ptr", SourceBitmap1, "uint*", &width1:=0) @@ -2591,7 +2591,7 @@ class ImageEqual extends ImagePut { ; Dimensions must be equal. if (width1 != width2 || height1 != height2) - return false + return False ; Create clones of the supplied source bitmaps in their original PixelFormat. ; This has the side effect of (1) removing negative stride and solves @@ -2654,6 +2654,6 @@ class ImageEqual extends ImagePut { DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap2) ; Compare stopped byte. - return (byte == size) ? true : false + return (byte == size) ? True : False } } ; End of ImageEqual class. \ No newline at end of file From 0d79b09c1b55b5982cde832cb4ab2b215e3565ac Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 17 Feb 2022 00:22:05 -0500 Subject: [PATCH 183/492] fix typo in comment --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 96d5fb35..43310437 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2358,7 +2358,7 @@ class ImagePut { ; An invalid extension is actually part of the filename. if !(extension ~= "^(?i:bmp|dib|rle|jpg|jpeg|jpe|jfif|gif|tif|tiff|png)$") { - ; Avoid appening an extra dot. + ; Avoid appending an extra period without an extension. if (extension != "") filename .= "." extension diff --git a/ImagePut.ahk b/ImagePut.ahk index c2769057..6836cb44 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2358,7 +2358,7 @@ class ImagePut { ; An invalid extension is actually part of the filename. if !(extension ~= "^(?i:bmp|dib|rle|jpg|jpeg|jpe|jfif|gif|tif|tiff|png)$") { - ; Avoid appening an extra dot. + ; Avoid appending an extra period without an extension. if (extension != "") filename .= "." extension From 27f2d49f03074969977063745441384d2a3ac6f2 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 17 Feb 2022 00:42:43 -0500 Subject: [PATCH 184/492] select_filepath creates numerical sequences --- ImagePut (for v1).ahk | 9 ++++++++- ImagePut.ahk | 9 ++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 43310437..35b425a1 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2378,7 +2378,14 @@ class ImagePut { filepath := directory "\" filename " (" A_Index ")." extension } - ; Filepath is complete! + ; Create a numeric sequence of files... + else if (filename == 0 or filename == 1) { + filepath := directory "\" filename "." extension + while FileExist(filepath) ; Check for collisions. + filepath := directory "\" A_Index "." extension + } + + ; Always overwrite specific filenames. else filepath := directory "\" filename "." extension } diff --git a/ImagePut.ahk b/ImagePut.ahk index 6836cb44..87b6bdb9 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2378,7 +2378,14 @@ class ImagePut { filepath := directory "\" filename " (" A_Index ")." extension } - ; Filepath is complete! + ; Create a numeric sequence of files... + else if (filename == 0 or filename == 1) { + filepath := directory "\" filename "." extension + while FileExist(filepath) ; Check for collisions. + filepath := directory "\" A_Index "." extension + } + + ; Always overwrite specific filenames. else filepath := directory "\" filename "." extension } From ca00111d702708628f792093befe4890eda66aee Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 17 Feb 2022 01:28:33 -0500 Subject: [PATCH 185/492] Allow filenames like "01" and "0001" --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 35b425a1..f1f55581 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2379,7 +2379,7 @@ class ImagePut { } ; Create a numeric sequence of files... - else if (filename == 0 or filename == 1) { + else if (filename == "0" or filename == "1") { filepath := directory "\" filename "." extension while FileExist(filepath) ; Check for collisions. filepath := directory "\" A_Index "." extension diff --git a/ImagePut.ahk b/ImagePut.ahk index 87b6bdb9..a7fcdf86 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2379,7 +2379,7 @@ class ImagePut { } ; Create a numeric sequence of files... - else if (filename == 0 or filename == 1) { + else if (filename == "0" or filename == "1") { filepath := directory "\" filename "." extension while FileExist(filepath) ; Check for collisions. filepath := directory "\" A_Index "." extension From c6eb0cae5a6580af377e15e4e01759fbcc418e94 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 24 Feb 2022 23:15:03 -0500 Subject: [PATCH 186/492] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 96e59b7f..50bf80c9 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,8 @@ * [Input Types & Output Functions](https://github.com/iseahound/ImagePut/wiki/Input-Types-&-Output-Functions) * [Crop, Scale, & Other Flags](https://github.com/iseahound/ImagePut/wiki/Crop,-Scale,-&-Other-Flags) * Chinese Documentation (中文) - [这里有一个中文版的使用教程](https://www.autoahk.com/archives/37246) +* [Internal Documentation](https://github.com/iseahound/ImagePut/wiki/Internal-Documentation) - Understanding how ImagePut works. +* [Engineering Challenges Q&A](https://github.com/iseahound/ImagePut/wiki/Engineering-Challenges-Q&A) - Click here to read some interesting stuff. Projects using ImagePut: From 091115e56d0075055ad63f54a78917a4cd38dc5f Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 24 Feb 2022 23:38:26 -0500 Subject: [PATCH 187/492] Replace GdipCreateBitmapFromFile with streams --- ImagePut (for v1).ahk | 5 ++++- ImagePut.ahk | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index f1f55581..8f24959f 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1165,7 +1165,10 @@ class ImagePut { } from_file(image) { - DllCall("gdiplus\GdipCreateBitmapFromFile", "wstr", image, "ptr*", pBitmap:=0) + ; This is faster than GdipCreateBitmapFromFile and does not lock the file. + pStream := this.get_file(image) + DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", pBitmap:=0) + ObjRelease(pStream) return pBitmap } diff --git a/ImagePut.ahk b/ImagePut.ahk index a7fcdf86..80aaadc5 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1165,7 +1165,10 @@ class ImagePut { } static from_file(image) { - DllCall("gdiplus\GdipCreateBitmapFromFile", "wstr", image, "ptr*", &pBitmap:=0) + ; This is faster than GdipCreateBitmapFromFile and does not lock the file. + pStream := this.get_file(image) + DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", &pBitmap:=0) + ObjRelease(pStream) return pBitmap } From c697138b188f0127963bc405c130bfc87c587249 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 24 Feb 2022 23:51:11 -0500 Subject: [PATCH 188/492] Add error checking to intermediate steps --- ImagePut (for v1).ahk | 6 ++++-- ImagePut.ahk | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 8f24959f..c72ced22 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -181,7 +181,8 @@ class ImagePut { and (p[1] == "") { ; For now, disallow any specification of extensions. ; Convert via stream intermediate. - pStream := this.ToStream(type, image, index) + if !(pStream := this.ToStream(type, image, index)) + throw Exception("pStream cannot be zero.") coimage := this.StreamToCoimage(cotype, pStream, p*) ; Prevents the stream object from being freed. @@ -201,7 +202,8 @@ class ImagePut { ; changes to the pixels while bypassing any copy-on-write and copy on LockBits(read) behavior. ; Convert via GDI+ bitmap intermediate. - pBitmap := this.ToBitmap(type, image, index) + if !(pBitmap := this.ToBitmap(type, image, index)) + throw Exception("pBitmap cannot be zero.") (validate) ? DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmap) : {} (crop) ? this.BitmapCrop(pBitmap, crop) : {} (scale) ? this.BitmapScale(pBitmap, scale) : {} diff --git a/ImagePut.ahk b/ImagePut.ahk index 80aaadc5..2897aab2 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -181,7 +181,8 @@ class ImagePut { and (!p.Has(1) || p[1] == "") { ; For now, disallow any specification of extensions. ; Convert via stream intermediate. - pStream := this.ToStream(type, image, index) + if !(pStream := this.ToStream(type, image, index)) + throw Error("pStream cannot be zero.") coimage := this.StreamToCoimage(cotype, pStream, p*) ; Prevents the stream object from being freed. @@ -201,7 +202,8 @@ class ImagePut { ; changes to the pixels while bypassing any copy-on-write and copy on LockBits(read) behavior. ; Convert via GDI+ bitmap intermediate. - pBitmap := this.ToBitmap(type, image, index) + if !(pBitmap := this.ToBitmap(type, image, index)) + throw Error("pBitmap cannot be zero.") (validate) ? DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmap) : {} (crop) ? this.BitmapCrop(&pBitmap, crop) : {} (scale) ? this.BitmapScale(&pBitmap, scale) : {} From feda1a8b12ee2c54905796ddf9f95860b0148a5b Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 25 Feb 2022 09:57:04 -0500 Subject: [PATCH 189/492] Refactor ImageDestroy into a nested class --- ImagePut (for v1).ahk | 105 +++++++++++++++++++++--------------------- ImagePut.ahk | 105 +++++++++++++++++++++--------------------- 2 files changed, 104 insertions(+), 106 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index c72ced22..a143a7d9 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -119,12 +119,12 @@ ImageShow(image, title := "", pos := "", style := 0x90000000, styleEx := 0x80088 return ImagePut("show", image, title, pos, style, styleEx, parent) } -ImagePut(cotype, image, p*) { - return ImagePut.call(cotype, image, p*) +ImageDestroy(image) { + return ImagePut.Destroy.call(image) } -ImageDestroy(image) { - return ImageDestroy.call(image) +ImagePut(cotype, image, p*) { + return ImagePut.call(cotype, image, p*) } ImageEqual(images*) { @@ -2447,70 +2447,69 @@ class ImagePut { . "`nYou can copy this message by pressing Ctrl + C.") } } -} ; End of ImagePut class. - -class ImageDestroy extends ImagePut { - - call(image) { - this.gdiplusStartup() - try type := this.DontVerifyImageType(image) - catch - type := this.ImageType(image) - this.Destroy(type, image) - this.gdiplusShutdown() - return - } + class Destroy extends ImagePut { - Destroy(type, image) { - if (type = "clipboard") { - if !DllCall("OpenClipboard", "ptr", A_ScriptHwnd) - throw Exception("Clipboard could not be opened.") - return DllCall("EmptyClipboard"), DllCall("CloseClipboard") + call(image) { + this.gdiplusStartup() + try type := this.DontVerifyImageType(image) + catch + type := this.ImageType(image) + this.Destroy(type, image) + this.gdiplusShutdown() + return } - if (type = "screenshot") - return DllCall("InvalidateRect", "ptr", 0, "ptr", 0, "int", 0) + Destroy(type, image) { + if (type = "clipboard") { + if !DllCall("OpenClipboard", "ptr", A_ScriptHwnd) + throw Exception("Clipboard could not be opened.") + return DllCall("EmptyClipboard"), DllCall("CloseClipboard") + } - if (type = "window") - return DllCall("DestroyWindow", "ptr", image) + if (type = "screenshot") + return DllCall("InvalidateRect", "ptr", 0, "ptr", 0, "int", 0) - if (type = "wallpaper") - return DllCall("SystemParametersInfo", "uint", SPI_SETDESKWALLPAPER := 0x14, "uint", 0, "ptr", 0, "uint", 2) + if (type = "window") + return DllCall("DestroyWindow", "ptr", image) - if (type = "cursor") - return DllCall("SystemParametersInfo", "uint", SPI_SETCURSORS := 0x57, "uint", 0, "ptr", 0, "uint", 0) + if (type = "wallpaper") + return DllCall("SystemParametersInfo", "uint", SPI_SETDESKWALLPAPER := 0x14, "uint", 0, "ptr", 0, "uint", 2) - if (type = "file") - FileDelete % image + if (type = "cursor") + return DllCall("SystemParametersInfo", "uint", SPI_SETCURSORS := 0x57, "uint", 0, "ptr", 0, "uint", 0) - if (type = "dc") { - if (DllCall("GetObjectType", "ptr", image, "uint") == 3) { ; OBJ_DC - hwnd := DllCall("WindowFromDC", "ptr", image, "ptr") - DllCall("ReleaseDC", "ptr", hwnd, "ptr", image) - } + if (type = "file") + FileDelete % image + + if (type = "dc") { + if (DllCall("GetObjectType", "ptr", image, "uint") == 3) { ; OBJ_DC + hwnd := DllCall("WindowFromDC", "ptr", image, "ptr") + DllCall("ReleaseDC", "ptr", hwnd, "ptr", image) + } - if (DllCall("GetObjectType", "ptr", image, "uint") == 10) { ; OBJ_MEMDC - obm := DllCall("CreateBitmap", "int", 0, "int", 0, "uint", 1, "uint", 1, "ptr", 0, "ptr") - hbm := DllCall("SelectObject", "ptr", image, "ptr", obm, "ptr") - DllCall("DeleteObject", "ptr", hbm) - DllCall("DeleteDC", "ptr", image) + if (DllCall("GetObjectType", "ptr", image, "uint") == 10) { ; OBJ_MEMDC + obm := DllCall("CreateBitmap", "int", 0, "int", 0, "uint", 1, "uint", 1, "ptr", 0, "ptr") + hbm := DllCall("SelectObject", "ptr", image, "ptr", obm, "ptr") + DllCall("DeleteObject", "ptr", hbm) + DllCall("DeleteDC", "ptr", image) + } } - } - if (type = "hBitmap") - return DllCall("DeleteObject", "ptr", image) + if (type = "hBitmap") + return DllCall("DeleteObject", "ptr", image) - if (type = "hIcon") - return DllCall("DestroyIcon", "ptr", image) + if (type = "hIcon") + return DllCall("DestroyIcon", "ptr", image) - if (type = "bitmap") - return !DllCall("gdiplus\GdipDisposeImage", "ptr", image) + if (type = "bitmap") + return !DllCall("gdiplus\GdipDisposeImage", "ptr", image) - if (type = "RandomAccessStream") or (type = "stream") - return !ObjRelease(image) - } -} ; End of ImageDestroy class. + if (type = "RandomAccessStream") or (type = "stream") + return !ObjRelease(image) + } + } ; End of Destroy class. +} ; End of ImagePut class. class ImageEqual extends ImagePut { diff --git a/ImagePut.ahk b/ImagePut.ahk index 2897aab2..a3399d72 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -118,15 +118,15 @@ ImagePutWindow(image, title := "", pos := "", style := 0x82C80000, styleEx := 0x ImageShow(image, title := "", pos := "", style := 0x90000000, styleEx := 0x80088, parent := "") { return ImagePut("show", image, title, pos, style, styleEx, parent) } + +ImageDestroy(image) { + return ImagePut.Destroy(image) +} /* ImagePut(cotype, image, p*) { return ImagePut.call(cotype, image, p*) } -ImageDestroy(image) { - return ImageDestroy.call(image) -} - ImageEqual(images*) { return ImageEqual.call(images*) } @@ -2447,70 +2447,69 @@ class ImagePut { . "`nYou can copy this message by pressing Ctrl + C.") } } -} ; End of ImagePut class. - -class ImageDestroy extends ImagePut { - - static call(image) { - this.gdiplusStartup() - try type := this.DontVerifyImageType(&image) - catch - type := this.ImageType(image) - this.Destroy(type, image) - this.gdiplusShutdown() - return - } + class Destroy extends ImagePut { - static Destroy(type, image) { - if (type = "clipboard") { - if !DllCall("OpenClipboard", "ptr", A_ScriptHwnd) - throw Error("Clipboard could not be opened.") - return ((_,*)=>_)(DllCall("EmptyClipboard"), DllCall("CloseClipboard")) + static call(image) { + this.gdiplusStartup() + try type := this.DontVerifyImageType(&image) + catch + type := this.ImageType(image) + this.Destroy(type, image) + this.gdiplusShutdown() + return } - if (type = "screenshot") - return DllCall("InvalidateRect", "ptr", 0, "ptr", 0, "int", 0) + static Destroy(type, image) { + if (type = "clipboard") { + if !DllCall("OpenClipboard", "ptr", A_ScriptHwnd) + throw Error("Clipboard could not be opened.") + return ((_,*)=>_)(DllCall("EmptyClipboard"), DllCall("CloseClipboard")) + } - if (type = "window") - return DllCall("DestroyWindow", "ptr", image) + if (type = "screenshot") + return DllCall("InvalidateRect", "ptr", 0, "ptr", 0, "int", 0) - if (type = "wallpaper") - return DllCall("SystemParametersInfo", "uint", SPI_SETDESKWALLPAPER := 0x14, "uint", 0, "ptr", 0, "uint", 2) + if (type = "window") + return DllCall("DestroyWindow", "ptr", image) - if (type = "cursor") - return DllCall("SystemParametersInfo", "uint", SPI_SETCURSORS := 0x57, "uint", 0, "ptr", 0, "uint", 0) + if (type = "wallpaper") + return DllCall("SystemParametersInfo", "uint", SPI_SETDESKWALLPAPER := 0x14, "uint", 0, "ptr", 0, "uint", 2) - if (type = "file") - FileDelete image + if (type = "cursor") + return DllCall("SystemParametersInfo", "uint", SPI_SETCURSORS := 0x57, "uint", 0, "ptr", 0, "uint", 0) - if (type = "dc") { - if (DllCall("GetObjectType", "ptr", image, "uint") == 3) { ; OBJ_DC - hwnd := DllCall("WindowFromDC", "ptr", image, "ptr") - DllCall("ReleaseDC", "ptr", hwnd, "ptr", image) - } + if (type = "file") + FileDelete image + + if (type = "dc") { + if (DllCall("GetObjectType", "ptr", image, "uint") == 3) { ; OBJ_DC + hwnd := DllCall("WindowFromDC", "ptr", image, "ptr") + DllCall("ReleaseDC", "ptr", hwnd, "ptr", image) + } - if (DllCall("GetObjectType", "ptr", image, "uint") == 10) { ; OBJ_MEMDC - obm := DllCall("CreateBitmap", "int", 0, "int", 0, "uint", 1, "uint", 1, "ptr", 0, "ptr") - hbm := DllCall("SelectObject", "ptr", image, "ptr", obm, "ptr") - DllCall("DeleteObject", "ptr", hbm) - DllCall("DeleteDC", "ptr", image) + if (DllCall("GetObjectType", "ptr", image, "uint") == 10) { ; OBJ_MEMDC + obm := DllCall("CreateBitmap", "int", 0, "int", 0, "uint", 1, "uint", 1, "ptr", 0, "ptr") + hbm := DllCall("SelectObject", "ptr", image, "ptr", obm, "ptr") + DllCall("DeleteObject", "ptr", hbm) + DllCall("DeleteDC", "ptr", image) + } } - } - if (type = "hBitmap") - return DllCall("DeleteObject", "ptr", image) + if (type = "hBitmap") + return DllCall("DeleteObject", "ptr", image) - if (type = "hIcon") - return DllCall("DestroyIcon", "ptr", image) + if (type = "hIcon") + return DllCall("DestroyIcon", "ptr", image) - if (type = "bitmap") - return !DllCall("gdiplus\GdipDisposeImage", "ptr", image) + if (type = "bitmap") + return !DllCall("gdiplus\GdipDisposeImage", "ptr", image) - if (type = "RandomAccessStream") or (type = "stream") - return !ObjRelease(image) - } -} ; End of ImageDestroy class. + if (type = "RandomAccessStream") or (type = "stream") + return !ObjRelease(image) + } + } ; End of Destroy class. +} ; End of ImagePut class. class ImageEqual extends ImagePut { From 75af1f94e7ed6387f9ff6be2b52f08f5eaa46fbb Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 25 Feb 2022 10:35:58 -0500 Subject: [PATCH 190/492] Stack Tracing for Bitmap out of scope error --- ImagePut (for v1).ahk | 4 ++-- ImagePut.ahk | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index a143a7d9..6484d4c4 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2441,10 +2441,10 @@ class ImagePut { ; Otherwise GDI+ has been truly unloaded from the script and objects are out of scope. if (cotype = "bitmap") - throw Exception("Out of scope error. `n`nIf you wish to handle raw pointers to GDI+ bitmaps, add the line" + throw Exception("Bitmap is out of scope. `n`nIf you wish to handle raw pointers to GDI+ bitmaps, add the line" . "`n`n`t`t" this.__class ".gdiplusStartup()`n`nor 'pToken := Gdip_Startup()' to the top of your script." . "`nAlternatively, use 'obj := ImagePutBuffer()' with 'obj.pBitmap'." - . "`nYou can copy this message by pressing Ctrl + C.") + . "`nYou can copy this message by pressing Ctrl + C.", -4) } } diff --git a/ImagePut.ahk b/ImagePut.ahk index a3399d72..99f95313 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2441,10 +2441,10 @@ class ImagePut { ; Otherwise GDI+ has been truly unloaded from the script and objects are out of scope. if (cotype = "bitmap") - throw Error("Out of scope error. `n`nIf you wish to handle raw pointers to GDI+ bitmaps, add the line" + throw Error("Bitmap is out of scope. `n`nIf you wish to handle raw pointers to GDI+ bitmaps, add the line" . "`n`n`t`t" this.prototype.__class ".gdiplusStartup()`n`nor 'pToken := Gdip_Startup()' to the top of your script." . "`nAlternatively, use 'obj := ImagePutBuffer()' with 'obj.pBitmap'." - . "`nYou can copy this message by pressing Ctrl + C.") + . "`nYou can copy this message by pressing Ctrl + C.", -3) } } From 3202a3b08d1fed880643c83b25c8df26df728c6b Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 25 Feb 2022 11:40:58 -0500 Subject: [PATCH 191/492] Add tests --- test/test_bitmaps_v1.ahk | 46 ++++++++++++++++++++++++++++++++++++++++ test/test_bitmaps_v2.ahk | 46 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 test/test_bitmaps_v1.ahk create mode 100644 test/test_bitmaps_v2.ahk diff --git a/test/test_bitmaps_v1.ahk b/test/test_bitmaps_v1.ahk new file mode 100644 index 00000000..d0c758af --- /dev/null +++ b/test/test_bitmaps_v1.ahk @@ -0,0 +1,46 @@ +#include ..\ImagePut (for v1).ahk +test_image := "https://i.pinimg.com/474x/9a/ba/60/9aba6040f5c0af8c93b388f5df24c121.jpg" +ImagePut.gdiplusStartup() +MsgBox Ready? + + +Start: + +for i, type1 in ["url", "file", "RandomAccessStream", "stream", "hex", "base64", "cursor", "hIcon", "hBitmap", "bitmap", "desktop", "window", "clipboard"] { + + ; Create the image to compare! + image1 := (type1 = "url") ? test_image : ImagePut(type1, {url: test_image}) + + for j, type2 in ["stream", "RandomAccessStream", "hex", "base64", "file", "cursor", "hIcon", "hBitmap", "bitmap", "desktop", "window", "clipboard"] { + + ; Log the conversion. + FileAppend % type1 " to " type2 "`n", % "log.txt" + + ; Do the conversion. + image2 := ImagePut(type2, image1) + + o1 := {} + o1[type1] := image1 + o2 := {} + o2[type2] := image2 + + if !ImageEqual(o1, o2) + FileAppend % "-----------> not equal <-----------`n", log.txt + + if !(type1 = "cursor" && type2 = "cursor") + ImagePut.Destroy.Destroy(type2, image2) + } + + ImagePut.Destroy.Destroy(type1, image1) +} + +if not ImagePut.decode { + ImagePut.decode := True + goto Start +} + + +if !WinExist("log ahk_class Notepad") + Run notepad log.txt +WinWait log ahk_class Notepad +WinActivate log ahk_class Notepad \ No newline at end of file diff --git a/test/test_bitmaps_v2.ahk b/test/test_bitmaps_v2.ahk new file mode 100644 index 00000000..a76094ba --- /dev/null +++ b/test/test_bitmaps_v2.ahk @@ -0,0 +1,46 @@ +#include ..\ImagePut.ahk +test_image := "https://i.pinimg.com/474x/9a/ba/60/9aba6040f5c0af8c93b388f5df24c121.jpg" +ImagePut.gdiplusStartup() +MsgBox "Ready?" + + +Start: + +for i, type1 in ["clipboard_png", "url", "file", "RandomAccessStream", "stream", "hex", "base64", "cursor", "hIcon", "hBitmap", "bitmap", "desktop", "window", "clipboard"] { + + ; Create the image to compare! + image1 := (type1 = "url") ? test_image : ImagePut(type1, {url: test_image}) + + for j, type2 in ["stream", "RandomAccessStream", "hex", "base64", "file", "cursor", "hIcon", "hBitmap", "bitmap", "desktop", "window", "clipboard"] { + + ; Log the conversion. + FileAppend type1 " to " type2 "`n", "log.txt" + + ; Do the conversion. + image2 := ImagePut(type2, image1) + + o1 := {} + o1.%type1% := image1 + o2 := {} + o2.%type2% := image2 + + if !ImageEqual(o1, o2) + FileAppend "-----------> not equal <-----------`n", "log.txt" + + if !(type1 = "cursor" && type2 = "cursor") + ImagePut.Destroy.Destroy(type2, image2) + } + + ImagePut.Destroy.Destroy(type1, image1) +} + +if not ImagePut.decode { + ImagePut.decode := True + goto Start +} + + +if !WinExist("log ahk_class Notepad") + Run "notepad log.txt" +WinWait "log ahk_class Notepad" +WinActivate "log ahk_class Notepad" \ No newline at end of file From d6ca86b14ed4579a32ffdfa7a1111dfb735e731f Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 25 Feb 2022 11:41:43 -0500 Subject: [PATCH 192/492] Allow clipboard_png to be an output type --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 6484d4c4..b7a9c505 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -526,7 +526,7 @@ class ImagePut { BitmapToCoimage(cotype, pBitmap, p1:="", p2:="", p3:="", p4:="", p5:="", p*) { ; BitmapToCoimage("clipboard", pBitmap) - if (cotype = "clipboard") + if (cotype = "clipboard" || cotype = "clipboard_png") return this.put_clipboard(pBitmap) ; BitmapToCoimage("buffer", pBitmap) diff --git a/ImagePut.ahk b/ImagePut.ahk index 99f95313..9c8bdd60 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -526,7 +526,7 @@ class ImagePut { static BitmapToCoimage(cotype, pBitmap, p1:="", p2:="", p3:="", p4:="", p5:="", p*) { ; BitmapToCoimage("clipboard", pBitmap) - if (cotype = "clipboard") + if (cotype = "clipboard" || cotype = "clipboard_png") return this.put_clipboard(pBitmap) ; BitmapToCoimage("buffer", pBitmap) From 065c25715550f3dadb283f9c0d9074604beb4942 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 25 Feb 2022 12:17:58 -0500 Subject: [PATCH 193/492] Add ImageWidth and ImageHeight --- ImagePut (for v1).ahk | 22 ++++++++++++++++++++++ ImagePut.ahk | 22 ++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index b7a9c505..4a40744e 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -123,6 +123,14 @@ ImageDestroy(image) { return ImagePut.Destroy.call(image) } +ImageWidth(image) { + return ImagePut.Dimensions(image)[1] +} + +ImageHeight(image) { + return ImagePut.Dimensions(image)[2] +} + ImagePut(cotype, image, p*) { return ImagePut.call(cotype, image, p*) } @@ -2448,6 +2456,20 @@ class ImagePut { } } + ; Get the image width and height. + Dimensions(image) { + this.gdiplusStartup() + try type := this.DontVerifyImageType(image) + catch + type := this.ImageType(image) + pBitmap := this.ToBitmap(type, image) + DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) + DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + this.gdiplusShutdown() + return [width, height] + } + class Destroy extends ImagePut { call(image) { diff --git a/ImagePut.ahk b/ImagePut.ahk index 9c8bdd60..e3e53236 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -122,6 +122,14 @@ ImageShow(image, title := "", pos := "", style := 0x90000000, styleEx := 0x80088 ImageDestroy(image) { return ImagePut.Destroy(image) } + +ImageWidth(image) { + return ImagePut.Dimensions(image)[1] +} + +ImageHeight(image) { + return ImagePut.Dimensions(image)[2] +} /* ImagePut(cotype, image, p*) { return ImagePut.call(cotype, image, p*) @@ -2448,6 +2456,20 @@ class ImagePut { } } + ; Get the image width and height. + static Dimensions(image) { + this.gdiplusStartup() + try type := this.DontVerifyImageType(&image) + catch + type := this.ImageType(image) + pBitmap := this.ToBitmap(type, image) + DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) + DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + this.gdiplusShutdown() + return [width, height] + } + class Destroy extends ImagePut { static call(image) { From 8b2ebb8e2c74a542389b717ef54089d141e53e6c Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 25 Feb 2022 13:38:41 -0500 Subject: [PATCH 194/492] ImagePutBuffer now has width and height properties --- ImagePut (for v1).ahk | 14 ++++++++++++++ ImagePut.ahk | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 4a40744e..a5196192 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1637,6 +1637,20 @@ class ImagePut { __Delete() { ImagePut.gdiplusShutdown("smart_pointer", this.pBitmap) } + + width { + get { + DllCall("gdiplus\GdipGetImageWidth", "ptr", this.pBitmap, "uint*", width:=0) + return width + } + } + + height { + get { + DllCall("gdiplus\GdipGetImageHeight", "ptr", this.pBitmap, "uint*", height:=0) + return height + } + } } put_screenshot(pBitmap, screenshot := "", alpha := "") { diff --git a/ImagePut.ahk b/ImagePut.ahk index e3e53236..4a7245e8 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1637,6 +1637,20 @@ class ImagePut { __Delete() { ImagePut.gdiplusShutdown("smart_pointer", this.pBitmap) } + + width { + get { + DllCall("gdiplus\GdipGetImageWidth", "ptr", this.pBitmap, "uint*", &width:=0) + return width + } + } + + height { + get { + DllCall("gdiplus\GdipGetImageHeight", "ptr", this.pBitmap, "uint*", &height:=0) + return height + } + } } static put_screenshot(pBitmap, screenshot := "", alpha := "") { From ff578efa0fa0441757299516275caed9eca176b5 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 25 Feb 2022 16:05:57 -0500 Subject: [PATCH 195/492] ExitApp --- test/test_bitmaps_v1.ahk | 3 ++- test/test_bitmaps_v2.ahk | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/test/test_bitmaps_v1.ahk b/test/test_bitmaps_v1.ahk index d0c758af..6efa4d66 100644 --- a/test/test_bitmaps_v1.ahk +++ b/test/test_bitmaps_v1.ahk @@ -43,4 +43,5 @@ if not ImagePut.decode { if !WinExist("log ahk_class Notepad") Run notepad log.txt WinWait log ahk_class Notepad -WinActivate log ahk_class Notepad \ No newline at end of file +WinActivate log ahk_class Notepad +ExitApp \ No newline at end of file diff --git a/test/test_bitmaps_v2.ahk b/test/test_bitmaps_v2.ahk index a76094ba..9da07685 100644 --- a/test/test_bitmaps_v2.ahk +++ b/test/test_bitmaps_v2.ahk @@ -43,4 +43,5 @@ if not ImagePut.decode { if !WinExist("log ahk_class Notepad") Run "notepad log.txt" WinWait "log ahk_class Notepad" -WinActivate "log ahk_class Notepad" \ No newline at end of file +WinActivate "log ahk_class Notepad" +ExitApp \ No newline at end of file From eb247f90b08836feaa804f5a50df6917884c576d Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 10 Mar 2022 11:35:40 -0500 Subject: [PATCH 196/492] d2dBitmap and wicBitmap detection --- ImagePut (for v1).ahk | 8 ++++++++ ImagePut.ahk | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index a5196192..106e5769 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -450,6 +450,14 @@ class ImagePut { ; A "RandomAccessStream" is a pointer to the IRandomAccessStream interface. try if ComObjQuery(image, "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}") return "RandomAccessStream", ObjRelease(image) + + ; A "wicBitmap" is a pointer to the IWICBitmap interface bitmap. + try if ComObjQuery(image, "{00000121-A8F2-4877-BA0A-FD2B6645FB94}") + return "wicBitmap", ObjRelease(image) + + ; A "d2dBitmap" is a pointer to the ID2D1Bitmap interface bitmap. + try if ComObjQuery(image, "{A2296057-EA42-4099-983B-539FB6505426}") + return "d2dBitmap", ObjRelease(image) } diff --git a/ImagePut.ahk b/ImagePut.ahk index 4a7245e8..330af460 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -450,6 +450,14 @@ class ImagePut { ; A "RandomAccessStream" is a pointer to the IRandomAccessStream interface. try if ComObjQuery(image, "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}") return "RandomAccessStream" + + ; A "wicBitmap" is a pointer to the IWICBitmap interface bitmap. + try if ComObjQuery(image, "{00000121-A8F2-4877-BA0A-FD2B6645FB94}") + return "wicBitmap" + + ; A "d2dBitmap" is a pointer to the ID2D1Bitmap interface bitmap. + try if ComObjQuery(image, "{A2296057-EA42-4099-983B-539FB6505426}") + return "d2dBitmap" } From 344aa49040793aafd6131c40ebab7ed65b3af241 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 10 Mar 2022 12:03:03 -0500 Subject: [PATCH 197/492] from_wicBitmap and put_wicBitmap --- ImagePut (for v1).ahk | 72 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 106e5769..d94756a8 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1518,6 +1518,38 @@ class ImagePut { return pStream } + from_wicBitmap(image) { + ; IWICBitmap::GetSize - https://github.com/tpn/winsdk-10/blob/9b69fd26ac0c7d0b83d378dba01080e93349c2ed/Include/10.0.16299.0/um/wincodec.h#L2207 + DllCall(NumGet(NumGet(image + 0) + A_PtrSize*3), "ptr", image, "uint*", width:=0, "uint*", height:=0) + + ; This is the 32-bit ARGB pBitmap (different from an hBitmap) that will receive the final converted pixels. + DllCall("gdiplus\GdipCreateBitmapFromScan0" + , "int", width, "int", height, "int", 0, "int", 0x26200A, "ptr", 0, "ptr*", pBitmap:=0) + + ; Transfer data from source pBitmap to an hBitmap manually. + VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 + NumPut( width, Rect, 8, "uint") ; Width + NumPut( height, Rect, 12, "uint") ; Height + VarSetCapacity(BitmapData, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + DllCall("gdiplus\GdipBitmapLockBits" + , "ptr", pBitmap + , "ptr", &Rect + , "uint", 2 ; ImageLockMode.WriteOnly + , "int", 0x26200A ; Format32bppArgb + , "ptr", &BitmapData) ; Contains the pointer (pBits) to the hbm. + + stride := NumGet(BitmapData, 8, "int") + Scan0 := NumGet(BitmapData, 16, "ptr") + + ; IWICBitmap::CopyPixels - https://github.com/tpn/winsdk-10/blob/9b69fd26ac0c7d0b83d378dba01080e93349c2ed/Include/10.0.16299.0/um/wincodec.h#L2225 + DllCall(NumGet(NumGet(image + 0) + A_PtrSize*7), "ptr", image, "ptr", &Rect, "uint", stride, "uint", stride * height, "ptr", Scan0) + + ; Unlock + DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", &BitmapData) + + return pBitmap + } + from_sprite(image) { ; Create a source pBitmap and extract the width and height. if DllCall("gdiplus\GdipCreateBitmapFromFile", "wstr", image, "ptr*", sBitmap:=0) @@ -2292,6 +2324,46 @@ class ImagePut { return pRandomAccessStream } + put_wicBitmap(pBitmap) { + ; Get Bitmap width and height. + DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) + DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) + + ; Initialize Windows Imaging Component. + IWICImagingFactory := ComObjCreate(CLSID_WICImagingFactory := "{CACAF262-9370-4615-A13B-9F5539DA4C0A}", IID_IWICImagingFactory := "{EC5EC8A9-C395-4314-9C77-54D7A935FF70}") + + ; WICBitmapNoCache must be 1! + ; IWICImagingFactory::CreateBitmap - https://github.com/tpn/winsdk-10/blob/9b69fd26ac0c7d0b83d378dba01080e93349c2ed/Include/10.0.16299.0/um/wincodec.h#L6447 + DllCall("ole32\CLSIDFromString", "wstr", GUID_WICPixelFormat32bppBGRA := "{6fddc324-4e03-4bfe-b185-3d77768dc90f}", "ptr", &CLSID := VarSetCapacity(CLSID, 16), "uint") + DllCall(NumGet(NumGet(IWICImagingFactory + 0) + A_PtrSize*17), "ptr", IWICImagingFactory, "uint", width, "uint", height, "ptr", &CLSID, "int", 1, "ptr*", wicBitmap:=0) + + VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 + NumPut( width, Rect, 8, "uint") ; Width + NumPut( height, Rect, 12, "uint") ; Height + + ; IWICBitmap::Lock - https://github.com/tpn/winsdk-10/blob/9b69fd26ac0c7d0b83d378dba01080e93349c2ed/Include/10.0.16299.0/um/wincodec.h#L2232 + DllCall(NumGet(NumGet(wicBitmap + 0) + A_PtrSize*8), "Ptr", wicBitmap, "Ptr", &Rect, "uint", 0x1, "ptr*", Lock:=0) + + ; IWICBitmapLock::GetDataPointer - https://github.com/tpn/winsdk-10/blob/9b69fd26ac0c7d0b83d378dba01080e93349c2ed/Include/10.0.16299.0/um/wincodec.h#L2104 + DllCall(NumGet(NumGet(Lock + 0) + A_PtrSize*5), "Ptr", Lock, "uint*", size:=0, "ptr*", Scan0:=0) + + VarSetCapacity(BitmapData, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + NumPut( 4 * width, BitmapData, 8, "int") ; Stride + NumPut( Scan0, BitmapData, 16, "ptr") ; Scan0 + DllCall("gdiplus\GdipBitmapLockBits" + , "ptr", pBitmap + , "ptr", &Rect + , "uint", 5 ; ImageLockMode.UserInputBuffer | ImageLockMode.ReadOnly + , "int", 0x26200A ; Format32bppArgb + , "ptr", &BitmapData) ; Contains the pointer (Scan0) to the WICBitmap. + DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", &BitmapData) + + ObjRelease(Lock) + ObjRelease(IWICImagingFactory) + + return wicBitmap + } + select_codec(pBitmap, extension, quality, ByRef pCodec, ByRef ep, ByRef ci, ByRef v) { ; Fill a buffer with the available image codec info. DllCall("gdiplus\GdipGetImageEncodersSize", "uint*", count:=0, "uint*", size:=0) From 520e25130414120e820b9c26b20733a3bb783de8 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 10 Mar 2022 12:06:30 -0500 Subject: [PATCH 198/492] Dispatch wicBitmap --- ImagePut (for v1).ahk | 7 +++++++ ImagePut.ahk | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index d94756a8..c91a29b3 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -534,6 +534,9 @@ class ImagePut { if (type = "RandomAccessStream") return this.from_RandomAccessStream(image) + if (type = "wicBitmap") + return this.from_wicBitmap(image) + if (type = "sprite") return this.from_sprite(image) @@ -613,6 +616,10 @@ class ImagePut { if (cotype = "RandomAccessStream") return this.put_RandomAccessStream(pBitmap, p1, p2) + ; BitmapToCoimage("wicBitmap", pBitmap) + if (cotype = "wicBitmap") + return this.put_wicBitmap(pBitmap) + throw Exception("Conversion from bitmap to " cotype " is not supported.") } diff --git a/ImagePut.ahk b/ImagePut.ahk index 330af460..93131852 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -534,6 +534,9 @@ class ImagePut { if (type = "RandomAccessStream") return this.from_RandomAccessStream(image) + if (type = "wicBitmap") + return this.from_wicBitmap(image) + if (type = "sprite") return this.from_sprite(image) @@ -613,6 +616,10 @@ class ImagePut { if (cotype = "RandomAccessStream") return this.put_RandomAccessStream(pBitmap, p1, p2) + ; BitmapToCoimage("wicBitmap", pBitmap) + if (cotype = "wicBitmap") + return this.put_wicBitmap(pBitmap) + throw Error("Conversion from bitmap to " cotype " is not supported.") } From 3bf482e828d5c3df984fcf635a83df28e5665554 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 10 Mar 2022 23:41:13 -0500 Subject: [PATCH 199/492] Calculate output size of base64 string --- ImagePut (for v1).ahk | 21 +++++++++++++++++++-- ImagePut.ahk | 21 +++++++++++++++++++-- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index c91a29b3..b4c90683 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2212,9 +2212,26 @@ class ImagePut { extension := "png" pStream := this.put_stream(pBitmap, extension, quality) - base64 := this.set_base64(pStream) + + ; Get a pointer to binary data. + DllCall("ole32\GetHGlobalFromStream", "ptr", pStream, "ptr*", hbin:=0, "uint") + bin := DllCall("GlobalLock", "ptr", hbin, "ptr") + size := DllCall("GlobalSize", "uint", bin, "uptr") + + ; Calculate the length of the base64 string. + flags := 0x40000001 ; CRYPT_STRING_NOCRLF | CRYPT_STRING_BASE64 + length := 4 * Ceil(size/3) + 1 ; An extra byte of padding is required. + VarSetCapacity(str, length) + + ; Using CryptBinaryToStringA saves about 2MB in memory. + DllCall("crypt32\CryptBinaryToStringA", "ptr", bin, "uint", size, "uint", flags, "ptr", &str, "uint*", length) + + ; Release binary data and stream. + DllCall("GlobalUnlock", "ptr", hbin) ObjRelease(pStream) - return base64 + + ; Return encoded string length minus 1. + return StrGet(&str, length, "CP0") } set_base64(pStream) { diff --git a/ImagePut.ahk b/ImagePut.ahk index 93131852..109c44a6 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2180,9 +2180,26 @@ class ImagePut { extension := "png" pStream := this.put_stream(pBitmap, extension, quality) - base64 := this.set_base64(pStream) + + ; Get a pointer to binary data. + DllCall("ole32\GetHGlobalFromStream", "ptr", pStream, "ptr*", &hbin:=0, "HRESULT") + bin := DllCall("GlobalLock", "ptr", hbin, "ptr") + size := DllCall("GlobalSize", "uint", bin, "uptr") + + ; Calculate the length of the base64 string. + flags := 0x40000001 ; CRYPT_STRING_NOCRLF | CRYPT_STRING_BASE64 + length := 4 * Ceil(size/3) + 1 ; An extra byte of padding is required. + str := Buffer(length) + + ; Using CryptBinaryToStringA saves about 2MB in memory. + DllCall("crypt32\CryptBinaryToStringA", "ptr", bin, "uint", size, "uint", flags, "ptr", str, "uint*", &length) + + ; Release binary data and stream. + DllCall("GlobalUnlock", "ptr", hbin) ObjRelease(pStream) - return base64 + + ; Return encoded string length minus 1. + return StrGet(str, length, "CP0") } static set_base64(pStream) { From 67ba5b78661de64edce3e6c4a3a930ee052171a2 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 10 Mar 2022 23:44:46 -0500 Subject: [PATCH 200/492] Pass a flags variable instead of parameter --- ImagePut (for v1).ahk | 12 ++++++++---- ImagePut.ahk | 12 ++++++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index b4c90683..3b5ccb87 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1218,7 +1218,8 @@ class ImagePut { get_hex(image) { image := Trim(image) image := RegExReplace(image, "^(0[xX])") - return this.get_string(image, 0xC) ; CRYPT_STRING_HEXRAW + flags := 0xC ; CRYPT_STRING_HEXRAW + return this.get_string(image, flags) } from_base64(image) { @@ -1231,7 +1232,8 @@ class ImagePut { get_base64(image) { image := Trim(image) image := RegExReplace(image, "^data:image\/[a-z]+;base64,") - return this.get_string(image, 0x1) ; CRYPT_STRING_BASE64 + flags := 0x1 ; CRYPT_STRING_BASE64 + return this.get_string(image, flags) } get_string(image, flags) { @@ -2203,7 +2205,8 @@ class ImagePut { } set_hex(pStream) { - return this.set_string(pStream, 0x4000000C) ; CRYPT_STRING_NOCRLF | CRYPT_STRING_HEXRAW + flags := 0x4000000C ; CRYPT_STRING_NOCRLF | CRYPT_STRING_HEXRAW + return this.set_string(pStream, flags) } put_base64(pBitmap, extension := "", quality := "") { @@ -2235,7 +2238,8 @@ class ImagePut { } set_base64(pStream) { - return this.set_string(pStream, 0x40000001) ; CRYPT_STRING_NOCRLF | CRYPT_STRING_BASE64 + flags := 0x40000001 ; CRYPT_STRING_NOCRLF | CRYPT_STRING_BASE64 + return this.set_string(pStream, flags) } set_string(pStream, flags) { diff --git a/ImagePut.ahk b/ImagePut.ahk index 109c44a6..0b4ad64c 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1218,7 +1218,8 @@ class ImagePut { static get_hex(image) { image := Trim(image) image := RegExReplace(image, "^(0[xX])") - return this.get_string(image, 0xC) ; CRYPT_STRING_HEXRAW + flags := 0xC ; CRYPT_STRING_HEXRAW + return this.get_string(image, flags) } static from_base64(image) { @@ -1231,7 +1232,8 @@ class ImagePut { static get_base64(image) { image := Trim(image) image := RegExReplace(image, "^data:image\/[a-z]+;base64,") - return this.get_string(image, 0x1) ; CRYPT_STRING_BASE64 + flags := 0x1 ; CRYPT_STRING_BASE64 + return this.get_string(image, flags) } static get_string(image, flags) { @@ -2171,7 +2173,8 @@ class ImagePut { } static set_hex(pStream) { - return this.set_string(pStream, 0x4000000C) ; CRYPT_STRING_NOCRLF | CRYPT_STRING_HEXRAW + flags := 0x4000000C ; CRYPT_STRING_NOCRLF | CRYPT_STRING_HEXRAW + return this.set_string(pStream, flags) } static put_base64(pBitmap, extension := "", quality := "") { @@ -2203,7 +2206,8 @@ class ImagePut { } static set_base64(pStream) { - return this.set_string(pStream, 0x40000001) ; CRYPT_STRING_NOCRLF | CRYPT_STRING_BASE64 + flags := 0x40000001 ; CRYPT_STRING_NOCRLF | CRYPT_STRING_BASE64 + return this.set_string(pStream, flags) } static set_string(pStream, flags) { From c23a2f8547eda051e78e0fc7f6bf0d651be3b947 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 10 Mar 2022 23:58:10 -0500 Subject: [PATCH 201/492] 2x the speed of set_base64 --- ImagePut (for v1).ahk | 16 +++++++++++++++- ImagePut.ahk | 16 +++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 3b5ccb87..47dca335 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2238,8 +2238,22 @@ class ImagePut { } set_base64(pStream) { + ; For compatibility with SHCreateMemStream do not use GetHGlobalFromStream. + DllCall("shlwapi\IStream_Size", "ptr", pStream, "ptr*", size:=0, "uint") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") + DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", &bin := VarSetCapacity(bin, size), "uint", size, "uint") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") + + ; Calculate the length of the base64 string. flags := 0x40000001 ; CRYPT_STRING_NOCRLF | CRYPT_STRING_BASE64 - return this.set_string(pStream, flags) + length := 4 * Ceil(size/3) + 1 ; An extra byte of padding is required. + VarSetCapacity(str, length) + + ; Using CryptBinaryToStringA saves about 2MB in memory. + DllCall("crypt32\CryptBinaryToStringA", "ptr", &bin, "uint", size, "uint", flags, "ptr", &str, "uint*", length) + + ; Return encoded string length minus 1. + return StrGet(&str, length, "CP0") } set_string(pStream, flags) { diff --git a/ImagePut.ahk b/ImagePut.ahk index 0b4ad64c..44a349c9 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2206,8 +2206,22 @@ class ImagePut { } static set_base64(pStream) { + ; For compatibility with SHCreateMemStream do not use GetHGlobalFromStream. + DllCall("shlwapi\IStream_Size", "ptr", pStream, "ptr*", &size:=0, "HRESULT") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") + DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", bin := Buffer(size), "uint", size, "HRESULT") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") + + ; Calculate the length of the base64 string. flags := 0x40000001 ; CRYPT_STRING_NOCRLF | CRYPT_STRING_BASE64 - return this.set_string(pStream, flags) + length := 4 * Ceil(size/3) + 1 ; An extra byte of padding is required. + str := Buffer(length) + + ; Using CryptBinaryToStringA saves about 2MB in memory. + DllCall("crypt32\CryptBinaryToStringA", "ptr", bin, "uint", size, "uint", flags, "ptr", str, "uint*", &length) + + ; Return encoded string length minus 1. + return StrGet(str, length, "CP0") } static set_string(pStream, flags) { From 8ec565c2230c939e99eaac8d59323c9d63f73b69 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 11 Mar 2022 00:05:55 -0500 Subject: [PATCH 202/492] 2x speed to hexadecimal --- ImagePut (for v1).ahk | 37 ++++++++++++++++++++++++++++++++++--- ImagePut.ahk | 37 ++++++++++++++++++++++++++++++++++--- 2 files changed, 68 insertions(+), 6 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 47dca335..1520b236 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2199,14 +2199,45 @@ class ImagePut { extension := "png" pStream := this.put_stream(pBitmap, extension, quality) - hex := this.set_hex(pStream) + + ; Get a pointer to binary data. + DllCall("ole32\GetHGlobalFromStream", "ptr", pStream, "ptr*", hbin:=0, "uint") + bin := DllCall("GlobalLock", "ptr", hbin, "ptr") + size := DllCall("GlobalSize", "uint", bin, "uptr") + + ; Calculate the length of the hexadecimal string. + flags := 0x4000000C ; CRYPT_STRING_NOCRLF | CRYPT_STRING_HEXRAW + length := 2 * size + 1 ; An extra byte of padding is required. + VarSetCapacity(str, length) + + ; Using CryptBinaryToStringA saves about 2MB in memory. + DllCall("crypt32\CryptBinaryToStringA", "ptr", bin, "uint", size, "uint", flags, "ptr", &str, "uint*", length) + + ; Release binary data and stream. + DllCall("GlobalUnlock", "ptr", hbin) ObjRelease(pStream) - return hex + + ; Return encoded string length minus 1. + return StrGet(&str, length, "CP0") } set_hex(pStream) { + ; For compatibility with SHCreateMemStream do not use GetHGlobalFromStream. + DllCall("shlwapi\IStream_Size", "ptr", pStream, "ptr*", size:=0, "uint") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") + DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", &bin := VarSetCapacity(bin, size), "uint", size, "uint") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") + + ; Calculate the length of the hexadecimal string. flags := 0x4000000C ; CRYPT_STRING_NOCRLF | CRYPT_STRING_HEXRAW - return this.set_string(pStream, flags) + length := 2 * size + 1 ; An extra byte of padding is required. + VarSetCapacity(str, length) + + ; Using CryptBinaryToStringA saves about 2MB in memory. + DllCall("crypt32\CryptBinaryToStringA", "ptr", &bin, "uint", size, "uint", flags, "ptr", &str, "uint*", length) + + ; Return encoded string length minus 1. + return StrGet(&str, length, "CP0") } put_base64(pBitmap, extension := "", quality := "") { diff --git a/ImagePut.ahk b/ImagePut.ahk index 44a349c9..56f4bba1 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2167,14 +2167,45 @@ class ImagePut { extension := "png" pStream := this.put_stream(pBitmap, extension, quality) - hex := this.set_hex(pStream) + + ; Get a pointer to binary data. + DllCall("ole32\GetHGlobalFromStream", "ptr", pStream, "ptr*", &hbin:=0, "HRESULT") + bin := DllCall("GlobalLock", "ptr", hbin, "ptr") + size := DllCall("GlobalSize", "uint", bin, "uptr") + + ; Calculate the length of the hexadecimal string. + flags := 0x4000000C ; CRYPT_STRING_NOCRLF | CRYPT_STRING_HEXRAW + length := 2 * size + 1 ; An extra byte of padding is required. + str := Buffer(length) + + ; Using CryptBinaryToStringA saves about 2MB in memory. + DllCall("crypt32\CryptBinaryToStringA", "ptr", bin, "uint", size, "uint", flags, "ptr", str, "uint*", &length) + + ; Release binary data and stream. + DllCall("GlobalUnlock", "ptr", hbin) ObjRelease(pStream) - return hex + + ; Return encoded string length minus 1. + return StrGet(str, length, "CP0") } static set_hex(pStream) { + ; For compatibility with SHCreateMemStream do not use GetHGlobalFromStream. + DllCall("shlwapi\IStream_Size", "ptr", pStream, "ptr*", &size:=0, "HRESULT") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") + DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", bin := Buffer(size), "uint", size, "HRESULT") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") + + ; Calculate the length of the hexadecimal string. flags := 0x4000000C ; CRYPT_STRING_NOCRLF | CRYPT_STRING_HEXRAW - return this.set_string(pStream, flags) + length := 2 * size + 1 ; An extra byte of padding is required. + str := Buffer(length) + + ; Using CryptBinaryToStringA saves about 2MB in memory. + DllCall("crypt32\CryptBinaryToStringA", "ptr", bin, "uint", size, "uint", flags, "ptr", str, "uint*", &length) + + ; Return encoded string length minus 1. + return StrGet(str, length, "CP0") } static put_base64(pBitmap, extension := "", quality := "") { From c10916190e5d761e2dddcb3887bba211261dba49 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 11 Mar 2022 00:08:54 -0500 Subject: [PATCH 203/492] Remove set_string and thanks noname! --- ImagePut (for v1).ahk | 21 ++++----------------- ImagePut.ahk | 21 ++++----------------- 2 files changed, 8 insertions(+), 34 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 1520b236..412746eb 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2194,6 +2194,8 @@ class ImagePut { } put_hex(pBitmap, extension := "", quality := "") { + ; Thanks noname - https://www.autohotkey.com/boards/viewtopic.php?style=7&p=144247#p144247 + ; Default extension is PNG for small sizes! if (extension == "") extension := "png" @@ -2241,6 +2243,8 @@ class ImagePut { } put_base64(pBitmap, extension := "", quality := "") { + ; Thanks noname - https://www.autohotkey.com/boards/viewtopic.php?style=7&p=144247#p144247 + ; Default extension is PNG for small sizes! if (extension == "") extension := "png" @@ -2287,23 +2291,6 @@ class ImagePut { return StrGet(&str, length, "CP0") } - set_string(pStream, flags) { - ; Thanks noname - https://www.autohotkey.com/boards/viewtopic.php?style=7&p=144247#p144247 - - ; For compatibility with SHCreateMemStream do not use GetHGlobalFromStream. - DllCall("shlwapi\IStream_Size", "ptr", pStream, "ptr*", size:=0, "uint") - DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") - DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", &bin := VarSetCapacity(bin, size), "uint", size, "uint") - DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") - - ; Using CryptBinaryToStringA saves about 2MB in memory. - DllCall("crypt32\CryptBinaryToStringA", "ptr", &bin, "uint", size, "uint", flags, "ptr", 0, "uint*", length:=0) - VarSetCapacity(str, length) - DllCall("crypt32\CryptBinaryToStringA", "ptr", &bin, "uint", size, "uint", flags, "ptr", &str, "uint*", length) - - return StrGet(&str, length, "CP0") - } - put_dc(pBitmap, alpha := "") { ; This may seem strange, but the hBitmap is selected onto the device context, ; and therefore cannot be deleted. In addition, the stock bitmap can never be leaked. diff --git a/ImagePut.ahk b/ImagePut.ahk index 56f4bba1..22b241f7 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2162,6 +2162,8 @@ class ImagePut { } static put_hex(pBitmap, extension := "", quality := "") { + ; Thanks noname - https://www.autohotkey.com/boards/viewtopic.php?style=7&p=144247#p144247 + ; Default extension is PNG for small sizes! if (extension == "") extension := "png" @@ -2209,6 +2211,8 @@ class ImagePut { } static put_base64(pBitmap, extension := "", quality := "") { + ; Thanks noname - https://www.autohotkey.com/boards/viewtopic.php?style=7&p=144247#p144247 + ; Default extension is PNG for small sizes! if (extension == "") extension := "png" @@ -2255,23 +2259,6 @@ class ImagePut { return StrGet(str, length, "CP0") } - static set_string(pStream, flags) { - ; Thanks noname - https://www.autohotkey.com/boards/viewtopic.php?style=7&p=144247#p144247 - - ; For compatibility with SHCreateMemStream do not use GetHGlobalFromStream. - DllCall("shlwapi\IStream_Size", "ptr", pStream, "ptr*", &size:=0, "HRESULT") - DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") - DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", bin := Buffer(size), "uint", size, "HRESULT") - DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") - - ; Using CryptBinaryToStringA saves about 2MB in memory. - DllCall("crypt32\CryptBinaryToStringA", "ptr", bin, "uint", size, "uint", flags, "ptr", 0, "uint*", &length:=0) - str := Buffer(length) - DllCall("crypt32\CryptBinaryToStringA", "ptr", bin, "uint", size, "uint", flags, "ptr", str, "uint*", length) - - return StrGet(str, length, "CP0") - } - static put_dc(pBitmap, alpha := "") { ; This may seem strange, but the hBitmap is selected onto the device context, ; and therefore cannot be deleted. In addition, the stock bitmap can never be leaked. From dbd22ef8916f62e1c411dd9febeb2d1fc61eb795 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 13 Mar 2022 18:13:07 -0400 Subject: [PATCH 204/492] 2x optimization for get_hex and get_base64 --- ImagePut (for v1).ahk | 30 ++++++++++++++++++++---------- ImagePut.ahk | 30 +++++++++++++++++++++--------- 2 files changed, 41 insertions(+), 19 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 412746eb..7f89ba0c 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1216,10 +1216,23 @@ class ImagePut { } get_hex(image) { + ; Trim whitespace and remove hexadecimal indicator. image := Trim(image) image := RegExReplace(image, "^(0[xX])") + + ; Retrieve the size of bytes from the length of the base64 string. flags := 0xC ; CRYPT_STRING_HEXRAW - return this.get_string(image, flags) + size := StrLen(image) / 2 + + hData := DllCall("GlobalAlloc", "uint", 0x2, "uptr", size, "ptr") + pData := DllCall("GlobalLock", "ptr", hData, "ptr") + + DllCall("crypt32\CryptStringToBinary" + , "ptr", &image, "uint", 0, "uint", flags, "ptr", pData, "uint*", size, "ptr", 0, "ptr", 0) + + DllCall("GlobalUnlock", "ptr", hData) + DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", True, "ptr*", pStream:=0, "uint") + return pStream } from_base64(image) { @@ -1230,16 +1243,14 @@ class ImagePut { } get_base64(image) { + ; Trim whitespace and remove mime type. image := Trim(image) - image := RegExReplace(image, "^data:image\/[a-z]+;base64,") - flags := 0x1 ; CRYPT_STRING_BASE64 - return this.get_string(image, flags) - } + image := RegExReplace(image, "(?i)^data:image\/[a-z]+;base64,") - get_string(image, flags) { - ; Ask for the size. Then allocate movable memory, copy to the buffer, unlock, and create stream. - DllCall("crypt32\CryptStringToBinary" - , "ptr", &image, "uint", 0, "uint", flags, "ptr", 0, "uint*", size:=0, "ptr", 0, "ptr", 0) + ; Retrieve the size of bytes from the length of the base64 string. + flags := 0x1 ; CRYPT_STRING_BASE64 + padding := (image ~= "==$") ? 2 : (image ~= "=$") ? 1 : 0 + size := 3 * (StrLen(image) / 4) - padding hData := DllCall("GlobalAlloc", "uint", 0x2, "uptr", size, "ptr") pData := DllCall("GlobalLock", "ptr", hData, "ptr") @@ -1249,7 +1260,6 @@ class ImagePut { DllCall("GlobalUnlock", "ptr", hData) DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", True, "ptr*", pStream:=0, "uint") - return pStream } diff --git a/ImagePut.ahk b/ImagePut.ahk index 22b241f7..8a0c7bec 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1216,10 +1216,24 @@ class ImagePut { } static get_hex(image) { + ; Trim whitespace and remove hexadecimal indicator. image := Trim(image) image := RegExReplace(image, "^(0[xX])") + + ; Retrieve the size of bytes from the length of the base64 string. flags := 0xC ; CRYPT_STRING_HEXRAW - return this.get_string(image, flags) + size := StrLen(image) / 2 + + hData := DllCall("GlobalAlloc", "uint", 0x2, "uptr", size, "ptr") + pData := DllCall("GlobalLock", "ptr", hData, "ptr") + + DllCall("crypt32\CryptStringToBinary" + , "ptr", StrPtr(image), "uint", 0, "uint", flags, "ptr", pData, "uint*", size, "ptr", 0, "ptr", 0) + + DllCall("GlobalUnlock", "ptr", hData) + DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", True, "ptr*", &pStream:=0, "HRESULT") + + return pStream } static from_base64(image) { @@ -1230,16 +1244,14 @@ class ImagePut { } static get_base64(image) { + ; Trim whitespace and remove mime type. image := Trim(image) - image := RegExReplace(image, "^data:image\/[a-z]+;base64,") - flags := 0x1 ; CRYPT_STRING_BASE64 - return this.get_string(image, flags) - } + image := RegExReplace(image, "(?i)^data:image\/[a-z]+;base64,") - static get_string(image, flags) { - ; Ask for the size. Then allocate movable memory, copy to the buffer, unlock, and create stream. - DllCall("crypt32\CryptStringToBinary" - , "ptr", StrPtr(image), "uint", 0, "uint", flags, "ptr", 0, "uint*", &size:=0, "ptr", 0, "ptr", 0) + ; Retrieve the size of bytes from the length of the base64 string. + flags := 0x1 ; CRYPT_STRING_BASE64 + padding := (image ~= "==$") ? 2 : (image ~= "=$") ? 1 : 0 + size := 3 * (StrLen(image) / 4) - padding hData := DllCall("GlobalAlloc", "uint", 0x2, "uptr", size, "ptr") pData := DllCall("GlobalLock", "ptr", hData, "ptr") From 5ce4e5d3bc0ba92cc81aa354918cd271ce9e27f6 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 13 Mar 2022 18:14:40 -0400 Subject: [PATCH 205/492] line breaks --- ImagePut.ahk | 2 -- 1 file changed, 2 deletions(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index 8a0c7bec..76c7c6b0 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1232,7 +1232,6 @@ class ImagePut { DllCall("GlobalUnlock", "ptr", hData) DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", True, "ptr*", &pStream:=0, "HRESULT") - return pStream } @@ -1261,7 +1260,6 @@ class ImagePut { DllCall("GlobalUnlock", "ptr", hData) DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", True, "ptr*", &pStream:=0, "HRESULT") - return pStream } From f55d8439a8b6e6f6a054eba789f23e72cc57cfc4 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 13 Mar 2022 18:32:56 -0400 Subject: [PATCH 206/492] Replace string pointer with string --- ImagePut (for v1).ahk | 4 ++-- ImagePut.ahk | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 7f89ba0c..93d2d7f1 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1228,7 +1228,7 @@ class ImagePut { pData := DllCall("GlobalLock", "ptr", hData, "ptr") DllCall("crypt32\CryptStringToBinary" - , "ptr", &image, "uint", 0, "uint", flags, "ptr", pData, "uint*", size, "ptr", 0, "ptr", 0) + , "str", image, "uint", 0, "uint", flags, "ptr", pData, "uint*", size, "ptr", 0, "ptr", 0) DllCall("GlobalUnlock", "ptr", hData) DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", True, "ptr*", pStream:=0, "uint") @@ -1256,7 +1256,7 @@ class ImagePut { pData := DllCall("GlobalLock", "ptr", hData, "ptr") DllCall("crypt32\CryptStringToBinary" - , "ptr", &image, "uint", 0, "uint", flags, "ptr", pData, "uint*", size, "ptr", 0, "ptr", 0) + , "str", image, "uint", 0, "uint", flags, "ptr", pData, "uint*", size, "ptr", 0, "ptr", 0) DllCall("GlobalUnlock", "ptr", hData) DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", True, "ptr*", pStream:=0, "uint") diff --git a/ImagePut.ahk b/ImagePut.ahk index 76c7c6b0..95ee911c 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1228,7 +1228,7 @@ class ImagePut { pData := DllCall("GlobalLock", "ptr", hData, "ptr") DllCall("crypt32\CryptStringToBinary" - , "ptr", StrPtr(image), "uint", 0, "uint", flags, "ptr", pData, "uint*", size, "ptr", 0, "ptr", 0) + , "str", image, "uint", 0, "uint", flags, "ptr", pData, "uint*", size, "ptr", 0, "ptr", 0) DllCall("GlobalUnlock", "ptr", hData) DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", True, "ptr*", &pStream:=0, "HRESULT") @@ -1256,7 +1256,7 @@ class ImagePut { pData := DllCall("GlobalLock", "ptr", hData, "ptr") DllCall("crypt32\CryptStringToBinary" - , "ptr", StrPtr(image), "uint", 0, "uint", flags, "ptr", pData, "uint*", size, "ptr", 0, "ptr", 0) + , "str", image, "uint", 0, "uint", flags, "ptr", pData, "uint*", size, "ptr", 0, "ptr", 0) DllCall("GlobalUnlock", "ptr", hData) DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", True, "ptr*", &pStream:=0, "HRESULT") From af1987086c7607bab09a4737600c65a441c9c1b2 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 17 Mar 2022 18:12:18 -0400 Subject: [PATCH 207/492] Add demo.ahk --- demo.ahk | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 demo.ahk diff --git a/demo.ahk b/demo.ahk new file mode 100644 index 00000000..a4801cad --- /dev/null +++ b/demo.ahk @@ -0,0 +1,12 @@ +#include *i ImagePut%A_TrayMenu%.ahk +#include *i ImagePut (for v%true%).ahk +#singleinstance force + +; This script runs on both AutoHotkey v1 and v2. +hwnd := ImagePutWindow("https://picsum.photos/500", "Thank you for trying ImagePut ♥") + +; Save the image as a file. +ImagePutFile(hwnd) + +; Copy the window handle to the clipboard. +ImagePutClipboard(hwnd) From fe423c88b574fa49ee3a2bb600d82c6c755c998a Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 18 Mar 2022 01:35:01 -0400 Subject: [PATCH 208/492] Refactor from_sprite to be 2x as fast Uses C pointers instead of arrays! --- ImagePut (for v1).ahk | 63 ++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 93d2d7f1..6cbc62fb 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1571,46 +1571,47 @@ class ImagePut { from_sprite(image) { ; Create a source pBitmap and extract the width and height. - if DllCall("gdiplus\GdipCreateBitmapFromFile", "wstr", image, "ptr*", sBitmap:=0) - if !(sBitmap := this.from_url(image)) + if !(pBitmap := this.from_file(image)) + if !(pBitmap := this.from_url(image)) throw Exception("Could not be loaded from a valid file path or URL.") ; Get Bitmap width and height. - DllCall("gdiplus\GdipGetImageWidth", "ptr", sBitmap, "uint*", width:=0) - DllCall("gdiplus\GdipGetImageHeight", "ptr", sBitmap, "uint*", height:=0) - - ; Create a destination pBitmap in 32-bit ARGB and get its device context though GDI+. - ; Note that a device context from a graphics context can only be drawn on, not read. - ; Also note that using a graphics context and blitting does not create a pixel perfect image. - ; Using a DIB and LockBits is about 5% faster. - DllCall("gdiplus\GdipCreateBitmapFromScan0" - , "int", width, "int", height, "int", 0, "int", 0x26200A, "ptr", 0, "ptr*", dBitmap:=0) - DllCall("gdiplus\GdipGetImageGraphicsContext", "ptr", dBitmap, "ptr*", dGraphics:=0) - DllCall("gdiplus\GdipGetDC", "ptr", dGraphics, "ptr*", ddc:=0) + DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) + DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) - ; Keep any existing transparency for whatever reason. - hBitmap := this.put_hBitmap(sBitmap) ; Could copy this code here for even more speed. + ; Transfer data from source pBitmap to an hBitmap manually. + VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 + NumPut( width, Rect, 8, "uint") ; Width + NumPut( height, Rect, 12, "uint") ; Height + VarSetCapacity(BitmapData, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + DllCall("gdiplus\GdipBitmapLockBits" + , "ptr", pBitmap + , "ptr", &Rect + , "uint", 3 ; ImageLockMode.ReadWrite + , "int", 0x26200A ; Format32bppArgb + , "ptr", &BitmapData) ; Contains the pointer (pBits) to the hbm. - ; Create a source device context and associate the source hBitmap. - sdc := DllCall("CreateCompatibleDC", "ptr", ddc, "ptr") - obm := DllCall("SelectObject", "ptr", sdc, "ptr", hBitmap, "ptr") + stride := NumGet(BitmapData, 8, "int") + Scan0 := NumGet(BitmapData, 16, "ptr") - ; Copy the image making the top-left pixel the color key. - DllCall("msimg32\TransparentBlt" - , "ptr", ddc, "int", 0, "int", 0, "int", width, "int", height ; destination - , "ptr", sdc, "int", 0, "int", 0, "int", width, "int", height ; source - , "uint", DllCall("GetPixel", "ptr", sdc, "int", 0, "int", 0)) ; RGB pixel. + static bin := 0 + if !bin { + ; C source code - https://godbolt.org/z/KTYG4x57x + code := (A_PtrSize == 4) + ? "VYnlg+wQi0UIiUX8i0UMjRSFAAAAAItFCAHQiUX46xeLRfyLADtFEHUJi0X8xwAAAAAAg0X8BItF/DtF+HLhycM=" + : "VUiJ5UiD7BBIiU0QiVUYRIlFIEiLRRBIiUX4i0UYSI0UhQAAAABIi0UQSAHQSIlF8OsaSItF+IsAO0UgdQpIi0X4xwAAAAAASINF+ARIi0X4SDtF8HLcSIPEEF3D" + padding := (code ~= "==$") ? 2 : (code ~= "=$") ? 1 : 0 + size := 3 * (StrLen(code) / 4) - padding + bin := DllCall("GlobalAlloc", "uint", 0, "uptr", size, "ptr") + DllCall("VirtualProtect", "ptr", bin, "ptr", size, "uint", 0x40, "uint*", old:=0) + DllCall("crypt32\CryptStringToBinary", "str", code, "uint", 0, "uint", 0x1, "ptr", bin, "uint*", size, "ptr", 0, "ptr", 0) + } - ; Cleanup the hBitmap and device contexts. - DllCall("SelectObject", "ptr", sdc, "ptr", obm) - DllCall("DeleteObject", "ptr", hBitmap) - DllCall("DeleteDC", "ptr", sdc) + DllCall(bin, "ptr", Scan0, "uint", width * height, "uint", NumGet(Scan0+0, "uint")) - ; Release the graphics context and delete. - DllCall("gdiplus\GdipReleaseDC", "ptr", dGraphics, "ptr", ddc) - DllCall("gdiplus\GdipDeleteGraphics", "ptr", dGraphics) + DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", &BitmapData) - return dBitmap + return pBitmap } put_clipboard(pBitmap) { From 8ee3751edc3f654a42f8d31e9a47eefeeddfdf1a Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 19 Mar 2022 10:55:21 -0400 Subject: [PATCH 209/492] 3x speed from_sprite by optimizing assembly --- ImagePut (for v1).ahk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 6cbc62fb..7d90073c 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1596,10 +1596,10 @@ class ImagePut { static bin := 0 if !bin { - ; C source code - https://godbolt.org/z/KTYG4x57x + ; C source code - https://godbolt.org/z/rvTWqrqv6 code := (A_PtrSize == 4) - ? "VYnlg+wQi0UIiUX8i0UMjRSFAAAAAItFCAHQiUX46xeLRfyLADtFEHUJi0X8xwAAAAAAg0X8BItF/DtF+HLhycM=" - : "VUiJ5UiD7BBIiU0QiVUYRIlFIEiLRRBIiUX4i0UYSI0UhQAAAABIi0UQSAHQSIlF8OsaSItF+IsAO0UgdQpIi0X4xwAAAAAASINF+ARIi0X4SDtF8HLcSIPEEF3D" + ? "VYnli0UIi1UMi00QjRSQOdBzDzkIdQbHAAAAAACDwATr7V3D" + : "idJIjQSRSDnBcxFEOQF1BscBAAAAAEiDwQTr6sM=" padding := (code ~= "==$") ? 2 : (code ~= "=$") ? 1 : 0 size := 3 * (StrLen(code) / 4) - padding bin := DllCall("GlobalAlloc", "uint", 0, "uptr", size, "ptr") From 110c4eb7f827c1613063ed80ba13503ea5afc63f Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 20 Mar 2022 00:39:56 -0400 Subject: [PATCH 210/492] Introduce keyword arguments for flexability --- ImagePut (for v1).ahk | 43 ++++++++++++++++++++++++------------------- ImagePut.ahk | 43 ++++++++++++++++++++++++------------------- 2 files changed, 48 insertions(+), 38 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 7d90073c..d4d24307 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -145,33 +145,37 @@ class ImagePut { static decode := False ; Forces conversion using a bitmap. The original file encoding will be lost. static validate := False ; Always copies image data into memory instead of passing references. - ; ImagePut() - Puts an image from anywhere to anywhere. - ; cotype - Output Type | string -> Case Insensitive. Read documentation. - ; image - Input Image | image -> Anything. Refer to ImageType(). - ; crop - Crop Coordinates | array -> [x,y,w,h] could be negative or percent. - ; scale - Scale Factor | real -> 2.0 - ; p* - Additional Parameters | variadic -> Extra parameters found in BitmapToCoimage(). + get(name, p*) { + return ObjHasKey(this, name) ? this.name : "" + } + call(cotype, image, p*) { - ; Extract parameters. + ; Conversion uses an intermediate: source -> intermediate -> destination + ; Pass keyword arguments to the source -> intermediate function. + ; Pass positional arguments to the intermediate -> destination function. + + ; Define parameters. if IsObject(image) { + + ; Save a copy of the keyword arguments. + keywords := image + keywords.base := {__get: this.get} ; Returns the empty string for unknown properties. + crop := ObjHasKey(image, "crop") ? image.crop : False scale := ObjHasKey(image, "scale") ? image.scale : False decode := ObjHasKey(image, "decode") ? image.decode : this.decode validate := ObjHasKey(image, "validate") ? image.validate : this.validate - index := ObjHasKey(image, "index") ? image.index : 0 - ; Dereference the image unknown. if ObjHasKey(image, "image") image := image.image } else { + keywords := {base: {__get: this.get}} ; Returns the empty string for unknown properties. crop := scale := False decode := this.decode validate := this.validate - - index := 0 } ; Start! @@ -189,7 +193,7 @@ class ImagePut { and (p[1] == "") { ; For now, disallow any specification of extensions. ; Convert via stream intermediate. - if !(pStream := this.ToStream(type, image, index)) + if !(pStream := this.ToStream(type, image, keywords)) throw Exception("pStream cannot be zero.") coimage := this.StreamToCoimage(cotype, pStream, p*) @@ -210,7 +214,7 @@ class ImagePut { ; changes to the pixels while bypassing any copy-on-write and copy on LockBits(read) behavior. ; Convert via GDI+ bitmap intermediate. - if !(pBitmap := this.ToBitmap(type, image, index)) + if !(pBitmap := this.ToBitmap(type, image, keywords)) throw Exception("pBitmap cannot be zero.") (validate) ? DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmap) : {} (crop) ? this.BitmapCrop(pBitmap, crop) : {} @@ -469,7 +473,7 @@ class ImagePut { throw Exception("Image type could not be identified.") } - ToBitmap(type, image, index := 0) { + ToBitmap(type, image, k := "") { if (type = "clipboard_png") return this.from_clipboard_png() @@ -499,7 +503,7 @@ class ImagePut { return this.from_cursor() if (type = "pdf") - return this.from_pdf(image, index) + return this.from_pdf(image, k.index) if (type = "url") return this.from_url(image) @@ -623,13 +627,13 @@ class ImagePut { throw Exception("Conversion from bitmap to " cotype " is not supported.") } - ToStream(type, image, index := 0) { + ToStream(type, image, k := "") { if (type = "clipboard_png") return this.get_clipboard_png() if (type = "pdf") - return this.get_pdf(image, index) + return this.get_pdf(image, k.index) if (type = "url") return this.get_url(image) @@ -1077,15 +1081,16 @@ class ImagePut { return pBitmap } - from_pdf(image, index := 0) { + from_pdf(image, index := "") { pStream := this.get_pdf(image, index) DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", pBitmap:=0) ObjRelease(pStream) return pBitmap } - get_pdf(image, index := 0) { + get_pdf(image, index := "") { ; Thanks malcev - https://www.autohotkey.com/boards/viewtopic.php?t=80735 + index := (index != "") ? index : 1 ; Create a stream from either a url or a file. pStream := this.is_url(image) ? this.get_url(image) : this.get_file(image) diff --git a/ImagePut.ahk b/ImagePut.ahk index 95ee911c..ef90cc61 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -145,33 +145,37 @@ class ImagePut { static decode := False ; Forces conversion using a bitmap. The original file encoding will be lost. static validate := False ; Always copies image data into memory instead of passing references. - ; ImagePut() - Puts an image from anywhere to anywhere. - ; cotype - Output Type | string -> Case Insensitive. Read documentation. - ; image - Input Image | image -> Anything. Refer to ImageType(). - ; crop - Crop Coordinates | array -> [x,y,w,h] could be negative or percent. - ; scale - Scale Factor | real -> 2.0 - ; p* - Additional Parameters | variadic -> Extra parameters found in BitmapToCoimage(). + static get(name, p*) { + return ObjHasOwnProp(this, name) ? this.name : "" + } + static call(cotype, image, p*) { - ; Extract parameters. + ; Conversion uses an intermediate: source -> intermediate -> destination + ; Pass keyword arguments to the source -> intermediate function. + ; Pass positional arguments to the intermediate -> destination function. + + ; Define parameters. if IsObject(image) { + + ; Save a copy of the keyword arguments. + keywords := image + keywords.base := {__get: this.get} ; Returns the empty string for unknown properties. + crop := ObjHasOwnProp(image, "crop") ? image.crop : False scale := ObjHasOwnProp(image, "scale") ? image.scale : False decode := ObjHasOwnProp(image, "decode") ? image.decode : this.decode validate := ObjHasOwnProp(image, "validate") ? image.validate : this.validate - index := ObjHasOwnProp(image, "index") ? image.index : 0 - ; Dereference the image unknown. if ObjHasOwnProp(image, "image") image := image.image } else { + keywords := {base: {__get: this.get}} ; Returns the empty string for unknown properties. crop := scale := False decode := this.decode validate := this.validate - - index := 0 } ; Start! @@ -189,7 +193,7 @@ class ImagePut { and (!p.Has(1) || p[1] == "") { ; For now, disallow any specification of extensions. ; Convert via stream intermediate. - if !(pStream := this.ToStream(type, image, index)) + if !(pStream := this.ToStream(type, image, keywords)) throw Error("pStream cannot be zero.") coimage := this.StreamToCoimage(cotype, pStream, p*) @@ -210,7 +214,7 @@ class ImagePut { ; changes to the pixels while bypassing any copy-on-write and copy on LockBits(read) behavior. ; Convert via GDI+ bitmap intermediate. - if !(pBitmap := this.ToBitmap(type, image, index)) + if !(pBitmap := this.ToBitmap(type, image, keywords)) throw Error("pBitmap cannot be zero.") (validate) ? DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmap) : {} (crop) ? this.BitmapCrop(&pBitmap, crop) : {} @@ -469,7 +473,7 @@ class ImagePut { throw Error("Image type could not be identified.") } - static ToBitmap(type, image, index := 0) { + static ToBitmap(type, image, k := "") { if (type = "clipboard_png") return this.from_clipboard_png() @@ -499,7 +503,7 @@ class ImagePut { return this.from_cursor() if (type = "pdf") - return this.from_pdf(image, index) + return this.from_pdf(image, k.index) if (type = "url") return this.from_url(image) @@ -623,13 +627,13 @@ class ImagePut { throw Error("Conversion from bitmap to " cotype " is not supported.") } - static ToStream(type, image, index := 0) { + static ToStream(type, image, k := "") { if (type = "clipboard_png") return this.get_clipboard_png() if (type = "pdf") - return this.get_pdf(image, index) + return this.get_pdf(image, k.index) if (type = "url") return this.get_url(image) @@ -1077,15 +1081,16 @@ class ImagePut { return pBitmap } - static from_pdf(image, index := 0) { + static from_pdf(image, index := "") { pStream := this.get_pdf(image, index) DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", &pBitmap:=0) ObjRelease(pStream) return pBitmap } - static get_pdf(image, index := 0) { + static get_pdf(image, index := "") { ; Thanks malcev - https://www.autohotkey.com/boards/viewtopic.php?t=80735 + index := (index != "") ? index : 1 ; Create a stream from either a url or a file. pStream := this.is_url(image) ? this.get_url(image) : this.get_file(image) From 0d1163a696fa0c1f41fbd85ee9b123f0e1eee1b3 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 20 Mar 2022 00:51:49 -0400 Subject: [PATCH 211/492] Add sentinel values in ToBitmap() This allows ImagePut.ToBitmap() to be called by itself for debugging and advanced users. --- ImagePut (for v1).ahk | 6 ++++++ ImagePut.ahk | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index d4d24307..55d3e040 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -475,6 +475,9 @@ class ImagePut { ToBitmap(type, image, k := "") { + ; Sentinel value + k := (k != "") ? k : {base: {__get: this.get}} ; Returns the empty string for unknown properties. + if (type = "clipboard_png") return this.from_clipboard_png() @@ -629,6 +632,9 @@ class ImagePut { ToStream(type, image, k := "") { + ; Sentinel value + k := (k != "") ? k : {base: {__get: this.get}} ; Returns the empty string for unknown properties. + if (type = "clipboard_png") return this.get_clipboard_png() diff --git a/ImagePut.ahk b/ImagePut.ahk index ef90cc61..90de1f6c 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -475,6 +475,9 @@ class ImagePut { static ToBitmap(type, image, k := "") { + ; Sentinel value + k := (k != "") ? k : {base: {__get: this.get}} ; Returns the empty string for unknown properties. + if (type = "clipboard_png") return this.from_clipboard_png() @@ -629,6 +632,9 @@ class ImagePut { static ToStream(type, image, k := "") { + ; Sentinel value + k := (k != "") ? k : {base: {__get: this.get}} ; Returns the empty string for unknown properties. + if (type = "clipboard_png") return this.get_clipboard_png() From f1807795715cd27c6beb87d5d65dab98fa574dc0 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 26 Mar 2022 01:29:40 -0400 Subject: [PATCH 212/492] Add Byte Order Mark... AGAIN --- ImagePut (for v1).ahk | 70 +++++++++++++++++++++++++++++++++++-------- ImagePut.ahk | 2 +- demo.ahk | 2 +- 3 files changed, 60 insertions(+), 14 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 55d3e040..2ca9bf92 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1700,27 +1700,73 @@ class ImagePut { } class BitmapBuffer { - __New(pBitmap) { - this.pBitmap := pBitmap + + __New(SourceBitmap) { ImagePut.gdiplusStartup() + + ; + + DllCall("gdiplus\GdipGetImageWidth", "ptr", SourceBitmap, "uint*", width:=0) + DllCall("gdiplus\GdipGetImageHeight", "ptr", SourceBitmap, "uint*", height:=0) + + size := 4 * width * height + ptr := DllCall("GlobalAlloc", "uint", 0, "uptr", size, "ptr") + + DllCall("gdiplus\GdipCreateBitmapFromScan0" + , "int", width, "int", height, "int", 4 * width, "int", 0x26200A, "ptr", ptr, "ptr*", pBitmap:=0) + + ; Transfer data from source pBitmap to an hBitmap manually. + VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 + NumPut( width, Rect, 8, "uint") ; Width + NumPut( height, Rect, 12, "uint") ; Height + VarSetCapacity(BitmapData, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + NumPut( 4 * width, BitmapData, 8, "int") ; Stride + NumPut( ptr, BitmapData, 16, "ptr") ; Scan0 + DllCall("gdiplus\GdipBitmapLockBits" + , "ptr", SourceBitmap + , "ptr", &Rect + , "uint", 5 ; ImageLockMode.UserInputBuffer | ImageLockMode.ReadOnly + , "int", 0x26200A ; Format32bppArgb + , "ptr", &BitmapData) ; Contains the pointer (pBits) to the hbm. + DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", SourceBitmap, "ptr", &BitmapData) + + this.width := width + this.height := height + this.ptr := ptr + this.size := size + this.pBitmap := pBitmap } __Delete() { ImagePut.gdiplusShutdown("smart_pointer", this.pBitmap) } - width { - get { - DllCall("gdiplus\GdipGetImageWidth", "ptr", this.pBitmap, "uint*", width:=0) - return width - } + __Get(x, y) { + return Format("0x{:X}", NumGet(this.ptr + 4*(y*this.width + x), "uint")) } - height { - get { - DllCall("gdiplus\GdipGetImageHeight", "ptr", this.pBitmap, "uint*", height:=0) - return height + PixelSearch(color) { + static bin := 0 + if !bin { + ; C source code - https://godbolt.org/z/rvTWqrqv6 + code := (A_PtrSize == 4) + ? "VYnlU4tFCItVDI0MkDnIcxCLXRA5GHUEicLrBYPABOvsidBbXcM=" + : "idJIjQSRSDnBcw9EOQF1BInI6wZIg8EE6+zD" + padding := (code ~= "==$") ? 2 : (code ~= "=$") ? 1 : 0 + size := 3 * (StrLen(code) / 4) - padding + bin := DllCall("GlobalAlloc", "uint", 0, "uptr", size, "ptr") + DllCall("VirtualProtect", "ptr", bin, "ptr", size, "uint", 0x40, "uint*", old:=0) + DllCall("crypt32\CryptStringToBinary", "str", code, "uint", 0, "uint", 0x1, "ptr", bin, "uint*", size, "ptr", 0, "ptr", 0) } + + ; Pass the width * height, but the size is returned due to C interpreting Scan0 as a integer pointer. + ; So when doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. + byte := DllCall(bin, "ptr", this.ptr, "uint", this.width * this.height, "uint", color, "int") + if (byte == this.ptr + this.size) + throw Exception("pixel not found") + x := mod((byte - this.ptr) / 4, this.width) + y := ((byte - this.ptr) / 4) // this.width + return {x:x, y:y} } } @@ -2561,7 +2607,7 @@ class ImagePut { ; Create a filepath based on the timestamp. if (filename == "") { - FormatTime, filename,, % "yyyy-MM-dd HH꞉mm꞉ss" + FormatTime, filename,, % "yyyy-MM-dd HH?mm?ss" filepath := directory "\" filename "." extension while FileExist(filepath) ; Check for collisions. filepath := directory "\" filename " (" A_Index ")." extension diff --git a/ImagePut.ahk b/ImagePut.ahk index 90de1f6c..64d0e46f 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2488,7 +2488,7 @@ class ImagePut { ; Create a filepath based on the timestamp. if (filename == "") { - filename := FormatTime(, "yyyy-MM-dd HH꞉mm꞉ss") + filename := FormatTime(, "yyyy-MM-dd HH?mm?ss") filepath := directory "\" filename "." extension while FileExist(filepath) ; Check for collisions. filepath := directory "\" filename " (" A_Index ")." extension diff --git a/demo.ahk b/demo.ahk index a4801cad..936f04d5 100644 --- a/demo.ahk +++ b/demo.ahk @@ -3,7 +3,7 @@ #singleinstance force ; This script runs on both AutoHotkey v1 and v2. -hwnd := ImagePutWindow("https://picsum.photos/500", "Thank you for trying ImagePut ♥") +hwnd := ImagePutWindow("https://picsum.photos/500", "Thank you for trying ImagePut ?") ; Save the image as a file. ImagePutFile(hwnd) From 59e7c52d4891becbbc68afa17947a0065fa0601b Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 26 Mar 2022 13:23:14 -0400 Subject: [PATCH 213/492] put_clipboard comments --- ImagePut (for v1).ahk | 14 +++++--------- ImagePut.ahk | 14 +++++--------- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 2ca9bf92..49892101 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1626,7 +1626,7 @@ class ImagePut { } put_clipboard(pBitmap) { - ; Standard Clipboard Formats - https://docs.microsoft.com/en-us/windows/win32/dataxchg/standard-clipboard-formats + ; Standard Clipboard Formats - https://www.codeproject.com/Reference/1091137/Windows-Clipboard-Formats ; Synthesized Clipboard Formats - https://docs.microsoft.com/en-us/windows/win32/dataxchg/clipboard-formats ; Open the clipboard with exponential backoff. @@ -1638,19 +1638,18 @@ class ImagePut { Sleep (2**(A_Index-1) * 30) else throw Exception("Clipboard could not be opened.") - ; If not opened with a valid window handle EmptyClipboard will crash the next call to OpenClipboard. + ; Requires a valid window handle via OpenClipboard or the next call to OpenClipboard will crash. DllCall("EmptyClipboard") ; #1 - Place the image onto the clipboard as a PNG stream. ; Thanks Jochen Arndt - https://www.codeproject.com/Answers/1207927/Saving-an-image-to-the-clipboard#answer3 ; Create a Stream whose underlying HGlobal must be referenced or lost forever. + ; Rescue the HGlobal after GDI+ has written the PNG to stream and release the stream. ; Please read: https://devblogs.microsoft.com/oldnewthing/20210929-00/?p=105742 DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "int", False, "ptr*", pStream:=0, "uint") this.select_codec(pBitmap, "png", "", pCodec, ep, ci, v) DllCall("gdiplus\GdipSaveImageToStream", "ptr", pBitmap, "ptr", pStream, "ptr", pCodec, "ptr", (ep) ? &ep : 0) - - ; Rescue the HGlobal after GDI+ has written the PNG to stream and release the stream. DllCall("ole32\GetHGlobalFromStream", "ptr", pStream, "uint*", hData:=0, "uint") ObjRelease(pStream) @@ -1683,15 +1682,12 @@ class ImagePut { ; Unlock to moveable memory because the clipboard requires it. DllCall("GlobalUnlock", "ptr", hdib) - ; Delete the temporary hBitmap. - DllCall("DeleteObject", "ptr", hbm) - ; CF_DIB (8) can be synthesized into CF_BITMAP (2), CF_PALETTE (9), and CF_DIBV5 (17). DllCall("SetClipboardData", "uint", 8, "ptr", hdib) - ; Close the clipboard. + ; Cleanup + DllCall("DeleteObject", "ptr", hbm) DllCall("CloseClipboard") - return "" } diff --git a/ImagePut.ahk b/ImagePut.ahk index 64d0e46f..923b0cb7 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1593,7 +1593,7 @@ class ImagePut { } static put_clipboard(pBitmap) { - ; Standard Clipboard Formats - https://docs.microsoft.com/en-us/windows/win32/dataxchg/standard-clipboard-formats + ; Standard Clipboard Formats - https://www.codeproject.com/Reference/1091137/Windows-Clipboard-Formats ; Synthesized Clipboard Formats - https://docs.microsoft.com/en-us/windows/win32/dataxchg/clipboard-formats ; Open the clipboard with exponential backoff. @@ -1605,19 +1605,18 @@ class ImagePut { Sleep (2**(A_Index-1) * 30) else throw Error("Clipboard could not be opened.") - ; If not opened with a valid window handle EmptyClipboard will crash the next call to OpenClipboard. + ; Requires a valid window handle via OpenClipboard or the next call to OpenClipboard will crash. DllCall("EmptyClipboard") ; #1 - Place the image onto the clipboard as a PNG stream. ; Thanks Jochen Arndt - https://www.codeproject.com/Answers/1207927/Saving-an-image-to-the-clipboard#answer3 ; Create a Stream whose underlying HGlobal must be referenced or lost forever. + ; Rescue the HGlobal after GDI+ has written the PNG to stream and release the stream. ; Please read: https://devblogs.microsoft.com/oldnewthing/20210929-00/?p=105742 DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "int", False, "ptr*", &pStream:=0, "HRESULT") this.select_codec(pBitmap, "png", "", &pCodec, &ep, &ci, &v) DllCall("gdiplus\GdipSaveImageToStream", "ptr", pBitmap, "ptr", pStream, "ptr", pCodec, "ptr", IsSet(ep) ? ep : 0) - - ; Rescue the HGlobal after GDI+ has written the PNG to stream and release the stream. DllCall("ole32\GetHGlobalFromStream", "ptr", pStream, "uint*", &hData:=0, "HRESULT") ObjRelease(pStream) @@ -1650,15 +1649,12 @@ class ImagePut { ; Unlock to moveable memory because the clipboard requires it. DllCall("GlobalUnlock", "ptr", hdib) - ; Delete the temporary hBitmap. - DllCall("DeleteObject", "ptr", hbm) - ; CF_DIB (8) can be synthesized into CF_BITMAP (2), CF_PALETTE (9), and CF_DIBV5 (17). DllCall("SetClipboardData", "uint", 8, "ptr", hdib) - ; Close the clipboard. + ; Cleanup + DllCall("DeleteObject", "ptr", hbm) DllCall("CloseClipboard") - return ClipboardAll() } From 191f5c6d04680db1ead6802f063936081da6871f Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 4 Apr 2022 09:56:32 -0400 Subject: [PATCH 214/492] Streamline determination of pStream extensions Don't add an extra pStream parameter to select_filepath --- ImagePut (for v1).ahk | 43 +++++++++++++++++++++++++++++++++++++------ ImagePut.ahk | 9 +++------ 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 49892101..d15a6ff3 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1691,6 +1691,40 @@ class ImagePut { return "" } + set_clipboard(pStream) { + this.select_extension(pStream, extension:="") + + if !(extension ~= "gif|png") { + DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", pBitmap:=0) + this.put_clipboard(pBitmap) + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + return "" + } + + ; Open the clipboard with exponential backoff. + loop + if DllCall("OpenClipboard", "ptr", A_ScriptHwnd) + break + else + if A_Index < 6 + Sleep (2**(A_Index-1) * 30) + else throw Exception("Clipboard could not be opened.") + + ; Requires a valid window handle via OpenClipboard or the next call to OpenClipboard will crash. + DllCall("EmptyClipboard") + + DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "int", False, "ptr*", pSharedStream:=0, "uint") + DllCall("shlwapi\IStream_Size", "ptr", pStream, "uptr*", size:=0, "uint") + DllCall("shlwapi\IStream_Copy", "ptr", pStream, "ptr", pSharedStream, "uint", size, "uint") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") + + DllCall("ole32\GetHGlobalFromStream", "ptr", pSharedStream, "uint*", hData:=0, "uint") + ObjRelease(pSharedStream) + DllCall("SetClipboardData", "uint", DllCall("RegisterClipboardFormat", "str", extension, "uint"), "ptr", hData) + DllCall("CloseClipboard") + return "" + } + put_buffer(pBitmap) { return new ImagePut.BitmapBuffer(pBitmap) } @@ -2237,7 +2271,8 @@ class ImagePut { set_file(pStream, filepath := "") { extension := "png" - this.select_filepath(filepath, extension, pStream) + this.select_extension(pStream, extension) + this.select_filepath(filepath, extension) ; For compatibility with SHCreateMemStream do not use GetHGlobalFromStream. DllCall("shlwapi\SHCreateStreamOnFileEx" @@ -2555,7 +2590,7 @@ class ImagePut { extension := "bmp" } - select_filepath(ByRef filepath, ByRef extension, pStream := "") { + select_filepath(ByRef filepath, ByRef extension) { ; Save default extension. default := extension @@ -2595,10 +2630,6 @@ class ImagePut { ; Restore default extension. extension := default - - ; Try extracting the filetype from the stream. - if (pStream) - this.select_extension(pStream, extension) } ; Create a filepath based on the timestamp. diff --git a/ImagePut.ahk b/ImagePut.ahk index 923b0cb7..abd84652 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2158,7 +2158,8 @@ class ImagePut { static set_file(pStream, filepath := "") { extension := "png" - this.select_filepath(&filepath, &extension, pStream) + this.select_extension(pStream, &extension) + this.select_filepath(&filepath, &extension) ; For compatibility with SHCreateMemStream do not use GetHGlobalFromStream. DllCall("shlwapi\SHCreateStreamOnFileEx" @@ -2436,7 +2437,7 @@ class ImagePut { extension := "bmp" } - static select_filepath(&filepath, &extension, pStream := "") { + static select_filepath(&filepath, &extension) { ; Save default extension. default := extension @@ -2476,10 +2477,6 @@ class ImagePut { ; Restore default extension. extension := default - - ; Try extracting the filetype from the stream. - if (pStream) - this.select_extension(pStream, &extension) } ; Create a filepath based on the timestamp. From 303d61f5b159b4eccb023cf5691af0b076d7e58a Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 24 Apr 2022 01:20:10 -0400 Subject: [PATCH 215/492] Use single line CryptStringToBinary --- ImagePut (for v1).ahk | 6 ++---- ImagePut.ahk | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index d15a6ff3..20275bf5 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1238,8 +1238,7 @@ class ImagePut { hData := DllCall("GlobalAlloc", "uint", 0x2, "uptr", size, "ptr") pData := DllCall("GlobalLock", "ptr", hData, "ptr") - DllCall("crypt32\CryptStringToBinary" - , "str", image, "uint", 0, "uint", flags, "ptr", pData, "uint*", size, "ptr", 0, "ptr", 0) + DllCall("crypt32\CryptStringToBinary", "str", image, "uint", 0, "uint", flags, "ptr", pData, "uint*", size, "ptr", 0, "ptr", 0) DllCall("GlobalUnlock", "ptr", hData) DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", True, "ptr*", pStream:=0, "uint") @@ -1266,8 +1265,7 @@ class ImagePut { hData := DllCall("GlobalAlloc", "uint", 0x2, "uptr", size, "ptr") pData := DllCall("GlobalLock", "ptr", hData, "ptr") - DllCall("crypt32\CryptStringToBinary" - , "str", image, "uint", 0, "uint", flags, "ptr", pData, "uint*", size, "ptr", 0, "ptr", 0) + DllCall("crypt32\CryptStringToBinary", "str", image, "uint", 0, "uint", flags, "ptr", pData, "uint*", size, "ptr", 0, "ptr", 0) DllCall("GlobalUnlock", "ptr", hData) DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", True, "ptr*", pStream:=0, "uint") diff --git a/ImagePut.ahk b/ImagePut.ahk index abd84652..d5f2d679 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1238,8 +1238,7 @@ class ImagePut { hData := DllCall("GlobalAlloc", "uint", 0x2, "uptr", size, "ptr") pData := DllCall("GlobalLock", "ptr", hData, "ptr") - DllCall("crypt32\CryptStringToBinary" - , "str", image, "uint", 0, "uint", flags, "ptr", pData, "uint*", size, "ptr", 0, "ptr", 0) + DllCall("crypt32\CryptStringToBinary", "str", image, "uint", 0, "uint", flags, "ptr", pData, "uint*", size, "ptr", 0, "ptr", 0) DllCall("GlobalUnlock", "ptr", hData) DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", True, "ptr*", &pStream:=0, "HRESULT") @@ -1266,8 +1265,7 @@ class ImagePut { hData := DllCall("GlobalAlloc", "uint", 0x2, "uptr", size, "ptr") pData := DllCall("GlobalLock", "ptr", hData, "ptr") - DllCall("crypt32\CryptStringToBinary" - , "str", image, "uint", 0, "uint", flags, "ptr", pData, "uint*", size, "ptr", 0, "ptr", 0) + DllCall("crypt32\CryptStringToBinary", "str", image, "uint", 0, "uint", flags, "ptr", pData, "uint*", size, "ptr", 0, "ptr", 0) DllCall("GlobalUnlock", "ptr", hData) DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", True, "ptr*", &pStream:=0, "HRESULT") From 4a9a38e117366236998eb44f0365bb9231e30768 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 24 Apr 2022 01:31:28 -0400 Subject: [PATCH 216/492] Add missing IStream_Reset to read from used streams --- ImagePut (for v1).ahk | 1 + 1 file changed, 1 insertion(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 20275bf5..e039cb35 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1713,6 +1713,7 @@ class ImagePut { DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "int", False, "ptr*", pSharedStream:=0, "uint") DllCall("shlwapi\IStream_Size", "ptr", pStream, "uptr*", size:=0, "uint") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") DllCall("shlwapi\IStream_Copy", "ptr", pStream, "ptr", pSharedStream, "uint", size, "uint") DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") From 8ab5ebf93dfb1835704d3a2e152c6c847b06cf00 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 24 Apr 2022 01:48:36 -0400 Subject: [PATCH 217/492] Remove padding variable --- ImagePut (for v1).ahk | 6 ++---- ImagePut.ahk | 3 +-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index e039cb35..0a4dec7f 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1259,8 +1259,7 @@ class ImagePut { ; Retrieve the size of bytes from the length of the base64 string. flags := 0x1 ; CRYPT_STRING_BASE64 - padding := (image ~= "==$") ? 2 : (image ~= "=$") ? 1 : 0 - size := 3 * (StrLen(image) / 4) - padding + size := StrLen(RTrim(image, "=")) * 3 // 4 hData := DllCall("GlobalAlloc", "uint", 0x2, "uptr", size, "ptr") pData := DllCall("GlobalLock", "ptr", hData, "ptr") @@ -1609,8 +1608,7 @@ class ImagePut { code := (A_PtrSize == 4) ? "VYnli0UIi1UMi00QjRSQOdBzDzkIdQbHAAAAAACDwATr7V3D" : "idJIjQSRSDnBcxFEOQF1BscBAAAAAEiDwQTr6sM=" - padding := (code ~= "==$") ? 2 : (code ~= "=$") ? 1 : 0 - size := 3 * (StrLen(code) / 4) - padding + size := StrLen(RTrim(code, "=")) * 3 // 4 bin := DllCall("GlobalAlloc", "uint", 0, "uptr", size, "ptr") DllCall("VirtualProtect", "ptr", bin, "ptr", size, "uint", 0x40, "uint*", old:=0) DllCall("crypt32\CryptStringToBinary", "str", code, "uint", 0, "uint", 0x1, "ptr", bin, "uint*", size, "ptr", 0, "ptr", 0) diff --git a/ImagePut.ahk b/ImagePut.ahk index d5f2d679..17a67797 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1259,8 +1259,7 @@ class ImagePut { ; Retrieve the size of bytes from the length of the base64 string. flags := 0x1 ; CRYPT_STRING_BASE64 - padding := (image ~= "==$") ? 2 : (image ~= "=$") ? 1 : 0 - size := 3 * (StrLen(image) / 4) - padding + size := StrLen(RTrim(image, "=")) * 3 // 4 hData := DllCall("GlobalAlloc", "uint", 0x2, "uptr", size, "ptr") pData := DllCall("GlobalLock", "ptr", hData, "ptr") From e32233e30d1133d26788b3c5f8f99355dac7fd5a Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 24 Apr 2022 02:47:49 -0400 Subject: [PATCH 218/492] Sync from_sprite for v2 --- ImagePut (for v1).ahk | 9 +++--- ImagePut.ahk | 69 ++++++++++++++++++++++--------------------- 2 files changed, 40 insertions(+), 38 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 0a4dec7f..77d9b87a 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1578,7 +1578,7 @@ class ImagePut { } from_sprite(image) { - ; Create a source pBitmap and extract the width and height. + ; Create a source pBitmap. if !(pBitmap := this.from_file(image)) if !(pBitmap := this.from_url(image)) throw Exception("Could not be loaded from a valid file path or URL.") @@ -1587,7 +1587,7 @@ class ImagePut { DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) - ; Transfer data from source pBitmap to an hBitmap manually. + ; Create a read write pixel buffer. VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 NumPut( width, Rect, 8, "uint") ; Width NumPut( height, Rect, 12, "uint") ; Height @@ -1598,10 +1598,9 @@ class ImagePut { , "uint", 3 ; ImageLockMode.ReadWrite , "int", 0x26200A ; Format32bppArgb , "ptr", &BitmapData) ; Contains the pointer (pBits) to the hbm. - - stride := NumGet(BitmapData, 8, "int") Scan0 := NumGet(BitmapData, 16, "ptr") + ; Generate machine code. static bin := 0 if !bin { ; C source code - https://godbolt.org/z/rvTWqrqv6 @@ -1614,8 +1613,10 @@ class ImagePut { DllCall("crypt32\CryptStringToBinary", "str", code, "uint", 0, "uint", 0x1, "ptr", bin, "uint*", size, "ptr", 0, "ptr", 0) } + ; Call colorkey. DllCall(bin, "ptr", Scan0, "uint", width * height, "uint", NumGet(Scan0+0, "uint")) + ; Replace bitmap. DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", &BitmapData) return pBitmap diff --git a/ImagePut.ahk b/ImagePut.ahk index 17a67797..2cdf0fb6 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1546,47 +1546,48 @@ class ImagePut { } static from_sprite(image) { - ; Create a source pBitmap and extract the width and height. - if DllCall("gdiplus\GdipCreateBitmapFromFile", "wstr", image, "ptr*", &sBitmap:=0) - if !(sBitmap := this.from_url(image)) + ; Create a source pBitmap. + if !(pBitmap := this.from_file(image)) + if !(pBitmap := this.from_url(image)) throw Error("Could not be loaded from a valid file path or URL.") ; Get Bitmap width and height. - DllCall("gdiplus\GdipGetImageWidth", "ptr", sBitmap, "uint*", &width:=0) - DllCall("gdiplus\GdipGetImageHeight", "ptr", sBitmap, "uint*", &height:=0) - - ; Create a destination pBitmap in 32-bit ARGB and get its device context though GDI+. - ; Note that a device context from a graphics context can only be drawn on, not read. - ; Also note that using a graphics context and blitting does not create a pixel perfect image. - ; Using a DIB and LockBits is about 5% faster. - DllCall("gdiplus\GdipCreateBitmapFromScan0" - , "int", width, "int", height, "int", 0, "int", 0x26200A, "ptr", 0, "ptr*", &dBitmap:=0) - DllCall("gdiplus\GdipGetImageGraphicsContext", "ptr", dBitmap, "ptr*", &dGraphics:=0) - DllCall("gdiplus\GdipGetDC", "ptr", dGraphics, "ptr*", &ddc:=0) - - ; Keep any existing transparency for whatever reason. - hBitmap := this.put_hBitmap(sBitmap) ; Could copy this code here for even more speed. - - ; Create a source device context and associate the source hBitmap. - sdc := DllCall("CreateCompatibleDC", "ptr", ddc, "ptr") - obm := DllCall("SelectObject", "ptr", sdc, "ptr", hBitmap, "ptr") + DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) + DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) - ; Copy the image making the top-left pixel the color key. - DllCall("msimg32\TransparentBlt" - , "ptr", ddc, "int", 0, "int", 0, "int", width, "int", height ; destination - , "ptr", sdc, "int", 0, "int", 0, "int", width, "int", height ; source - , "uint", DllCall("GetPixel", "ptr", sdc, "int", 0, "int", 0)) ; RGB pixel. + ; Create a read write pixel buffer. + Rect := Buffer(16, 0) ; sizeof(Rect) = 16 + NumPut( "uint", width, Rect, 8) ; Width + NumPut( "uint", height, Rect, 12) ; Height + BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + DllCall("gdiplus\GdipBitmapLockBits" + , "ptr", pBitmap + , "ptr", Rect + , "uint", 3 ; ImageLockMode.ReadWrite + , "int", 0x26200A ; Format32bppArgb + , "ptr", BitmapData) ; Contains the pointer (pBits) to the hbm. + Scan0 := NumGet(BitmapData, 16, "ptr") + + ; Generate machine code. + static bin := 0 + if !bin { + ; C source code - https://godbolt.org/z/rvTWqrqv6 + code := (A_PtrSize == 4) + ? "VYnli0UIi1UMi00QjRSQOdBzDzkIdQbHAAAAAACDwATr7V3D" + : "idJIjQSRSDnBcxFEOQF1BscBAAAAAEiDwQTr6sM=" + size := StrLen(RTrim(code, "=")) * 3 // 4 + bin := DllCall("GlobalAlloc", "uint", 0, "uptr", size, "ptr") + DllCall("VirtualProtect", "ptr", bin, "ptr", size, "uint", 0x40, "uint*", &old:=0) + DllCall("crypt32\CryptStringToBinary", "str", code, "uint", 0, "uint", 0x1, "ptr", bin, "uint*", size, "ptr", 0, "ptr", 0) + } - ; Cleanup the hBitmap and device contexts. - DllCall("SelectObject", "ptr", sdc, "ptr", obm) - DllCall("DeleteObject", "ptr", hBitmap) - DllCall("DeleteDC", "ptr", sdc) + ; Call colorkey. + DllCall(bin, "ptr", Scan0, "uint", width * height, "uint", NumGet(Scan0+0, "uint")) - ; Release the graphics context and delete. - DllCall("gdiplus\GdipReleaseDC", "ptr", dGraphics, "ptr", ddc) - DllCall("gdiplus\GdipDeleteGraphics", "ptr", dGraphics) + ; Replace bitmap. + DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", BitmapData) - return dBitmap + return pBitmap } static put_clipboard(pBitmap) { From b5a31e64fbd92901ea899d8388876193198b7e5c Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 24 Apr 2022 02:50:22 -0400 Subject: [PATCH 219/492] Remove +0 in v2 code --- ImagePut.ahk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index 2cdf0fb6..dc9fc519 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1582,7 +1582,7 @@ class ImagePut { } ; Call colorkey. - DllCall(bin, "ptr", Scan0, "uint", width * height, "uint", NumGet(Scan0+0, "uint")) + DllCall(bin, "ptr", Scan0, "uint", width * height, "uint", NumGet(Scan0, "uint")) ; Replace bitmap. DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", BitmapData) From dcd3e071fbf80ea79f0928d2e45058e2edc2b375 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 24 Apr 2022 02:54:08 -0400 Subject: [PATCH 220/492] comments --- ImagePut (for v1).ahk | 4 ++-- ImagePut.ahk | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 77d9b87a..e14b6e20 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1597,7 +1597,7 @@ class ImagePut { , "ptr", &Rect , "uint", 3 ; ImageLockMode.ReadWrite , "int", 0x26200A ; Format32bppArgb - , "ptr", &BitmapData) ; Contains the pointer (pBits) to the hbm. + , "ptr", &BitmapData) Scan0 := NumGet(BitmapData, 16, "ptr") ; Generate machine code. @@ -1616,7 +1616,7 @@ class ImagePut { ; Call colorkey. DllCall(bin, "ptr", Scan0, "uint", width * height, "uint", NumGet(Scan0+0, "uint")) - ; Replace bitmap. + ; Write pixels to bitmap. DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", &BitmapData) return pBitmap diff --git a/ImagePut.ahk b/ImagePut.ahk index dc9fc519..fa4881b5 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1565,7 +1565,7 @@ class ImagePut { , "ptr", Rect , "uint", 3 ; ImageLockMode.ReadWrite , "int", 0x26200A ; Format32bppArgb - , "ptr", BitmapData) ; Contains the pointer (pBits) to the hbm. + , "ptr", BitmapData) Scan0 := NumGet(BitmapData, 16, "ptr") ; Generate machine code. @@ -1584,7 +1584,7 @@ class ImagePut { ; Call colorkey. DllCall(bin, "ptr", Scan0, "uint", width * height, "uint", NumGet(Scan0, "uint")) - ; Replace bitmap. + ; Write pixels to bitmap. DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", BitmapData) return pBitmap From fe64bd9cd7b5f9fa76ec4c66d087851bb2bfb8c4 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 24 Apr 2022 03:18:00 -0400 Subject: [PATCH 221/492] Fix size types --- ImagePut (for v1).ahk | 12 ++++++------ ImagePut.ahk | 10 +++++----- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index e14b6e20..45f73ad5 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1711,7 +1711,7 @@ class ImagePut { DllCall("EmptyClipboard") DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "int", False, "ptr*", pSharedStream:=0, "uint") - DllCall("shlwapi\IStream_Size", "ptr", pStream, "uptr*", size:=0, "uint") + DllCall("shlwapi\IStream_Size", "ptr", pStream, "uint64*", size:=0, "uint") DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") DllCall("shlwapi\IStream_Copy", "ptr", pStream, "ptr", pSharedStream, "uint", size, "uint") DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") @@ -2281,7 +2281,7 @@ class ImagePut { , "ptr", 0 ; pstmTemplate (reserved) , "ptr*", pFileStream:=0 , "uint") - DllCall("shlwapi\IStream_Size", "ptr", pStream, "ptr*", size:=0, "uint") + DllCall("shlwapi\IStream_Size", "ptr", pStream, "uint64*", size:=0, "uint") DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") DllCall("shlwapi\IStream_Copy", "ptr", pStream, "ptr", pFileStream, "uint", size, "uint") DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") @@ -2302,7 +2302,7 @@ class ImagePut { ; Get a pointer to binary data. DllCall("ole32\GetHGlobalFromStream", "ptr", pStream, "ptr*", hbin:=0, "uint") bin := DllCall("GlobalLock", "ptr", hbin, "ptr") - size := DllCall("GlobalSize", "uint", bin, "uptr") + size := DllCall("GlobalSize", "ptr", bin, "uptr") ; Calculate the length of the hexadecimal string. flags := 0x4000000C ; CRYPT_STRING_NOCRLF | CRYPT_STRING_HEXRAW @@ -2322,7 +2322,7 @@ class ImagePut { set_hex(pStream) { ; For compatibility with SHCreateMemStream do not use GetHGlobalFromStream. - DllCall("shlwapi\IStream_Size", "ptr", pStream, "ptr*", size:=0, "uint") + DllCall("shlwapi\IStream_Size", "ptr", pStream, "uint64*", size:=0, "uint") DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", &bin := VarSetCapacity(bin, size), "uint", size, "uint") DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") @@ -2351,7 +2351,7 @@ class ImagePut { ; Get a pointer to binary data. DllCall("ole32\GetHGlobalFromStream", "ptr", pStream, "ptr*", hbin:=0, "uint") bin := DllCall("GlobalLock", "ptr", hbin, "ptr") - size := DllCall("GlobalSize", "uint", bin, "uptr") + size := DllCall("GlobalSize", "ptr", bin, "uptr") ; Calculate the length of the base64 string. flags := 0x40000001 ; CRYPT_STRING_NOCRLF | CRYPT_STRING_BASE64 @@ -2371,7 +2371,7 @@ class ImagePut { set_base64(pStream) { ; For compatibility with SHCreateMemStream do not use GetHGlobalFromStream. - DllCall("shlwapi\IStream_Size", "ptr", pStream, "ptr*", size:=0, "uint") + DllCall("shlwapi\IStream_Size", "ptr", pStream, "uint64*", size:=0, "uint") DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", &bin := VarSetCapacity(bin, size), "uint", size, "uint") DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") diff --git a/ImagePut.ahk b/ImagePut.ahk index fa4881b5..52c60bbd 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2168,7 +2168,7 @@ class ImagePut { , "ptr", 0 ; pstmTemplate (reserved) , "ptr*", &pFileStream:=0 ,"HRESULT") - DllCall("shlwapi\IStream_Size", "ptr", pStream, "ptr*", &size:=0, "HRESULT") + DllCall("shlwapi\IStream_Size", "ptr", pStream, "uint64*", &size:=0, "HRESULT") DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") DllCall("shlwapi\IStream_Copy", "ptr", pStream, "ptr", pFileStream, "uint", size, "HRESULT") DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") @@ -2189,7 +2189,7 @@ class ImagePut { ; Get a pointer to binary data. DllCall("ole32\GetHGlobalFromStream", "ptr", pStream, "ptr*", &hbin:=0, "HRESULT") bin := DllCall("GlobalLock", "ptr", hbin, "ptr") - size := DllCall("GlobalSize", "uint", bin, "uptr") + size := DllCall("GlobalSize", "ptr", bin, "uptr") ; Calculate the length of the hexadecimal string. flags := 0x4000000C ; CRYPT_STRING_NOCRLF | CRYPT_STRING_HEXRAW @@ -2209,7 +2209,7 @@ class ImagePut { static set_hex(pStream) { ; For compatibility with SHCreateMemStream do not use GetHGlobalFromStream. - DllCall("shlwapi\IStream_Size", "ptr", pStream, "ptr*", &size:=0, "HRESULT") + DllCall("shlwapi\IStream_Size", "ptr", pStream, "uint64*", &size:=0, "HRESULT") DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", bin := Buffer(size), "uint", size, "HRESULT") DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") @@ -2238,7 +2238,7 @@ class ImagePut { ; Get a pointer to binary data. DllCall("ole32\GetHGlobalFromStream", "ptr", pStream, "ptr*", &hbin:=0, "HRESULT") bin := DllCall("GlobalLock", "ptr", hbin, "ptr") - size := DllCall("GlobalSize", "uint", bin, "uptr") + size := DllCall("GlobalSize", "ptr", bin, "uptr") ; Calculate the length of the base64 string. flags := 0x40000001 ; CRYPT_STRING_NOCRLF | CRYPT_STRING_BASE64 @@ -2258,7 +2258,7 @@ class ImagePut { static set_base64(pStream) { ; For compatibility with SHCreateMemStream do not use GetHGlobalFromStream. - DllCall("shlwapi\IStream_Size", "ptr", pStream, "ptr*", &size:=0, "HRESULT") + DllCall("shlwapi\IStream_Size", "ptr", pStream, "uint64*", &size:=0, "HRESULT") DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", bin := Buffer(size), "uint", size, "HRESULT") DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") From 1a147e4c25885f6bdd22b1d04eb4f666e406e7aa Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 24 Apr 2022 04:32:28 -0400 Subject: [PATCH 222/492] Refactor DontVerifyImageType and add IsImageObject --- ImagePut (for v1).ahk | 166 +++++++++++++----------------------------- ImagePut.ahk | 164 ++++++++++++----------------------------- 2 files changed, 96 insertions(+), 234 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 45f73ad5..2dc2402d 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -145,10 +145,6 @@ class ImagePut { static decode := False ; Forces conversion using a bitmap. The original file encoding will be lost. static validate := False ; Always copies image data into memory instead of passing references. - get(name, p*) { - return ObjHasKey(this, name) ? this.name : "" - } - call(cotype, image, p*) { ; Conversion uses an intermediate: source -> intermediate -> destination @@ -156,7 +152,7 @@ class ImagePut { ; Pass positional arguments to the intermediate -> destination function. ; Define parameters. - if IsObject(image) { + if this.IsImageObject(image) { ; Save a copy of the keyword arguments. keywords := image @@ -232,127 +228,63 @@ class ImagePut { return coimage } + get(name, p*) { + return ObjHasKey(this, name) ? this.name : "" + } + + static ImageTypes := + ( Join + [ + "clipboard_png", + "clipboard", + "object", + "buffer", + "screenshot", + "window", + "desktop", + "wallpaper", + "cursor", + "pdf", + "url", + "file", + "hex", + "base64", + "monitor", + "dc", + "hBitmap", + "hIcon", + "bitmap", + "stream", + "RandomAccessStream", + "wicBitmap", + "d2dBitmap", + "sprite" + ] + ) + + IsImageObject(image) { + if IsObject(image) + for i, prop in image + for j, type in this.ImageTypes + if prop = type + return True + return False + } + DontVerifyImageType(ByRef image) { if !IsObject(image) throw Exception("Must be an object.") - ; Check for image type declarations. - ; Assumes that the user is telling the truth. - - if ObjHasKey(image, "clipboard_png") { - image := image.clipboard_png - return "clipboard_png" - } - - if ObjHasKey(image, "clipboard") { - image := image.clipboard - return "clipboard" - } - - if ObjHasKey(image, "object") { - image := image.object - return "object" - } - - if ObjHasKey(image, "buffer") { - image := image.buffer - return "buffer" - } - - if ObjHasKey(image, "screenshot") { - image := image.screenshot - return "screenshot" - } - - if ObjHasKey(image, "window") { - image := image.window - return "window" - } - - if ObjHasKey(image, "desktop") { - image := image.desktop - return "desktop" - } - - if ObjHasKey(image, "wallpaper") { - image := image.wallpaper - return "wallpaper" - } - - if ObjHasKey(image, "cursor") { - image := image.cursor - return "cursor" - } - - if ObjHasKey(image, "pdf") { - image := image.pdf - return "pdf" - } - - if ObjHasKey(image, "url") { - image := image.url - return "url" - } - - if ObjHasKey(image, "file") { - image := image.file - return "file" - } - - if ObjHasKey(image, "hex") { - image := image.hex - return "hex" - } - - if ObjHasKey(image, "base64") { - image := image.base64 - return "base64" - } - - if ObjHasKey(image, "monitor") { - image := image.monitor - return "monitor" - } - - if ObjHasKey(image, "dc") { - image := image.dc - return "dc" - } - - if ObjHasKey(image, "hBitmap") { - image := image.hBitmap - return "hBitmap" - } - - if ObjHasKey(image, "hIcon") { - image := image.hIcon - return "hIcon" - } - - if ObjHasKey(image, "bitmap") { - image := image.bitmap - return "bitmap" - } - - if ObjHasKey(image, "stream") { - image := image.stream - return "stream" - } - - if ObjHasKey(image, "RandomAccessStream") { - image := image.RandomAccessStream - return "RandomAccessStream" - } - - if ObjHasKey(image, "sprite") { - image := image.sprite - return "sprite" - } + for i, type in this.ImageTypes + if ObjHasKey(image, type) + if image := image[type] + return type throw Exception("Invalid type.") } + ImageType(image) { ; Throw if the image is an empty string. if (image == "") { diff --git a/ImagePut.ahk b/ImagePut.ahk index 52c60bbd..ecd54273 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -145,10 +145,6 @@ class ImagePut { static decode := False ; Forces conversion using a bitmap. The original file encoding will be lost. static validate := False ; Always copies image data into memory instead of passing references. - static get(name, p*) { - return ObjHasOwnProp(this, name) ? this.name : "" - } - static call(cotype, image, p*) { ; Conversion uses an intermediate: source -> intermediate -> destination @@ -156,7 +152,7 @@ class ImagePut { ; Pass positional arguments to the intermediate -> destination function. ; Define parameters. - if IsObject(image) { + if this.IsImageObject(image) { ; Save a copy of the keyword arguments. keywords := image @@ -232,123 +228,57 @@ class ImagePut { return coimage } + static get(name, p*) { + return ObjHasOwnProp(this, name) ? this.name : "" + } + + static ImageTypes := [ + "clipboard_png", + "clipboard", + "object", + "buffer", + "screenshot", + "window", + "desktop", + "wallpaper", + "cursor", + "pdf", + "url", + "file", + "hex", + "base64", + "monitor", + "dc", + "hBitmap", + "hIcon", + "bitmap", + "stream", + "RandomAccessStream", + "wicBitmap", + "d2dBitmap", + "sprite" + ] + + + + static IsImageObject(image) { + if IsObject(image) + for prop in image.OwnProps() + for type in this.ImageTypes + if prop = type + return True + return False + } + static DontVerifyImageType(&image) { if !IsObject(image) throw Error("Must be an object.") - ; Check for image type declarations. - ; Assumes that the user is telling the truth. - - if ObjHasOwnProp(image, "clipboard_png") { - image := image.clipboard_png - return "clipboard_png" - } - - if ObjHasOwnProp(image, "clipboard") { - image := image.clipboard - return "clipboard" - } - - if ObjHasOwnProp(image, "object") { - image := image.object - return "object" - } - - if ObjHasOwnProp(image, "buffer") { - image := image.buffer - return "buffer" - } - - if ObjHasOwnProp(image, "screenshot") { - image := image.screenshot - return "screenshot" - } - - if ObjHasOwnProp(image, "window") { - image := image.window - return "window" - } - - if ObjHasOwnProp(image, "desktop") { - image := image.desktop - return "desktop" - } - - if ObjHasOwnProp(image, "wallpaper") { - image := image.wallpaper - return "wallpaper" - } - - if ObjHasOwnProp(image, "cursor") { - image := image.cursor - return "cursor" - } - - if ObjHasOwnProp(image, "pdf") { - image := image.pdf - return "pdf" - } - - if ObjHasOwnProp(image, "url") { - image := image.url - return "url" - } - - if ObjHasOwnProp(image, "file") { - image := image.file - return "file" - } - - if ObjHasOwnProp(image, "hex") { - image := image.hex - return "hex" - } - - if ObjHasOwnProp(image, "base64") { - image := image.base64 - return "base64" - } - - if ObjHasOwnProp(image, "monitor") { - image := image.monitor - return "monitor" - } - - if ObjHasOwnProp(image, "dc") { - image := image.dc - return "dc" - } - - if ObjHasOwnProp(image, "hBitmap") { - image := image.hBitmap - return "hBitmap" - } - - if ObjHasOwnProp(image, "hIcon") { - image := image.hIcon - return "hIcon" - } - - if ObjHasOwnProp(image, "bitmap") { - image := image.bitmap - return "bitmap" - } - - if ObjHasOwnProp(image, "stream") { - image := image.stream - return "stream" - } - - if ObjHasOwnProp(image, "RandomAccessStream") { - image := image.RandomAccessStream - return "RandomAccessStream" - } - - if ObjHasOwnProp(image, "sprite") { - image := image.sprite - return "sprite" - } + for type in this.ImageTypes + if ObjHasOwnProp(image, type) + if image := image.%type% + return type throw Error("Invalid type.") } From 6d8ab819d008e92998e51428c0ab9ab5f4105f92 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 24 Apr 2022 04:35:01 -0400 Subject: [PATCH 223/492] Standardize for loop syntax --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 2dc2402d..a04fadf3 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -398,7 +398,7 @@ class ImagePut { ; For more helpful error messages: Catch file names without extensions! - for extension in ["bmp","dib","rle","jpg","jpeg","jpe","jfif","gif","tif","tiff","png","ico","exe","dll"] + for i, extension in ["bmp","dib","rle","jpg","jpeg","jpe","jfif","gif","tif","tiff","png","ico","exe","dll"] if FileExist(image "." extension) throw Exception("A ." extension " file extension is required!") diff --git a/ImagePut.ahk b/ImagePut.ahk index ecd54273..7af9a38c 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2589,7 +2589,7 @@ class ImageEqual extends ImagePut { } ; If there are multiple images, compare each subsequent image to the first. - for i, image in images { + for image in images { if (A_Index != 1) { ; Guess the type of the image. From 0d3d54f0c58cabc6f95829a11baec02bb5b78017 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 24 Apr 2022 04:40:30 -0400 Subject: [PATCH 224/492] Improve error message for missing file extension --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index a04fadf3..5e5d3f84 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -400,7 +400,7 @@ class ImagePut { ; For more helpful error messages: Catch file names without extensions! for i, extension in ["bmp","dib","rle","jpg","jpeg","jpe","jfif","gif","tif","tiff","png","ico","exe","dll"] if FileExist(image "." extension) - throw Exception("A ." extension " file extension is required!") + throw Exception("A ." extension " file extension is required!", -4) throw Exception("Image type could not be identified.") } diff --git a/ImagePut.ahk b/ImagePut.ahk index 7af9a38c..ffeb57f5 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -398,7 +398,7 @@ class ImagePut { ; For more helpful error messages: Catch file names without extensions! for extension in ["bmp","dib","rle","jpg","jpeg","jpe","jfif","gif","tif","tiff","png","ico","exe","dll"] if FileExist(image "." extension) - throw Error("A ." extension " file extension is required!") + throw Error("A ." extension " file extension is required!", -3) throw Error("Image type could not be identified.") } From 290c22be4c2fe5ce58752a956dad5773eb9a57e8 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 24 Apr 2022 04:43:42 -0400 Subject: [PATCH 225/492] line spacing --- ImagePut (for v1).ahk | 1 - ImagePut.ahk | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 5e5d3f84..056cbc68 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -284,7 +284,6 @@ class ImagePut { throw Exception("Invalid type.") } - ImageType(image) { ; Throw if the image is an empty string. if (image == "") { diff --git a/ImagePut.ahk b/ImagePut.ahk index ffeb57f5..f7fba2fd 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -261,6 +261,7 @@ class ImagePut { + static IsImageObject(image) { if IsObject(image) for prop in image.OwnProps() From 6ff80cc35265bd49b5e03054f85483f8de206a57 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 24 Apr 2022 11:31:59 -0400 Subject: [PATCH 226/492] Refactor DontVerifyImageType to use sentinel values --- ImagePut (for v1).ahk | 66 ++++++++++++++++------------------------ ImagePut.ahk | 70 +++++++++++++++++-------------------------- 2 files changed, 54 insertions(+), 82 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 056cbc68..f128df0b 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -147,41 +147,19 @@ class ImagePut { call(cotype, image, p*) { - ; Conversion uses an intermediate: source -> intermediate -> destination - ; Pass keyword arguments to the source -> intermediate function. - ; Pass positional arguments to the intermediate -> destination function. - - ; Define parameters. - if this.IsImageObject(image) { - - ; Save a copy of the keyword arguments. - keywords := image - keywords.base := {__get: this.get} ; Returns the empty string for unknown properties. - - crop := ObjHasKey(image, "crop") ? image.crop : False - scale := ObjHasKey(image, "scale") ? image.scale : False - decode := ObjHasKey(image, "decode") ? image.decode : this.decode - validate := ObjHasKey(image, "validate") ? image.validate : this.validate - - ; Dereference the image unknown. - if ObjHasKey(image, "image") - image := image.image - - } else { - keywords := {base: {__get: this.get}} ; Returns the empty string for unknown properties. - crop := scale := False - decode := this.decode - validate := this.validate - } - ; Start! this.gdiplusStartup() ; Take a guess as to what the image might be. (>95% accuracy!) - try type := this.DontVerifyImageType(image) + try type := this.DontVerifyImageType(image, keywords) catch type := this.ImageType(image) + crop := keywords.crop + scale := keywords.scale + decode := keywords.decode ? keywords.decode : this.decode + validate := keywords.validate ? keywords.validate : this.validate + ; #1 - Stream intermediate. if not decode and not crop and not scale and (type ~= "^(?i:clipboard_png|pdf|url|file|stream|RandomAccessStream|hex|base64)$") @@ -262,25 +240,33 @@ class ImagePut { ] ) - IsImageObject(image) { - if IsObject(image) - for i, prop in image - for j, type in this.ImageTypes - if prop = type - return True - return False - } + DontVerifyImageType(ByRef image, ByRef keywords := "") { - DontVerifyImageType(ByRef image) { + ; Sentinel value: Returns the empty string for unknown properties. + keywords := {base: {__get: this.get}} + ; Try ImageType. if !IsObject(image) throw Exception("Must be an object.") + ; Goto ImageType. + if ObjHasKey(image, "image") { + keywords := image + keywords.base := {__get: this.get} + image := image.image + throw Exception("Must catch this error with ImageType.") + } + + ; Skip ImageType. for i, type in this.ImageTypes - if ObjHasKey(image, type) - if image := image[type] - return type + if ObjHasKey(image, type) { + keywords := image + keywords.base := {__get: this.get} + image := image[type] + return type + } + ; Continue ImageType. throw Exception("Invalid type.") } diff --git a/ImagePut.ahk b/ImagePut.ahk index f7fba2fd..6f5b2387 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -142,46 +142,24 @@ ImageEqual(images*) { class ImagePut { - static decode := False ; Forces conversion using a bitmap. The original file encoding will be lost. - static validate := False ; Always copies image data into memory instead of passing references. + static decode := False ; Forces conversion using a bitmap. The original file encoding will be lost. + static validate := False ; Always copies image data into memory instead of passing references. static call(cotype, image, p*) { - ; Conversion uses an intermediate: source -> intermediate -> destination - ; Pass keyword arguments to the source -> intermediate function. - ; Pass positional arguments to the intermediate -> destination function. - - ; Define parameters. - if this.IsImageObject(image) { - - ; Save a copy of the keyword arguments. - keywords := image - keywords.base := {__get: this.get} ; Returns the empty string for unknown properties. - - crop := ObjHasOwnProp(image, "crop") ? image.crop : False - scale := ObjHasOwnProp(image, "scale") ? image.scale : False - decode := ObjHasOwnProp(image, "decode") ? image.decode : this.decode - validate := ObjHasOwnProp(image, "validate") ? image.validate : this.validate - - ; Dereference the image unknown. - if ObjHasOwnProp(image, "image") - image := image.image - - } else { - keywords := {base: {__get: this.get}} ; Returns the empty string for unknown properties. - crop := scale := False - decode := this.decode - validate := this.validate - } - ; Start! this.gdiplusStartup() ; Take a guess as to what the image might be. (>95% accuracy!) - try type := this.DontVerifyImageType(&image) + try type := this.DontVerifyImageType(&image, &keywords) catch type := this.ImageType(image) + crop := keywords.crop + scale := keywords.scale + decode := keywords.decode ? keywords.decode : this.decode + validate := keywords.validate ? keywords.validate : this.validate + ; #1 - Stream intermediate. if not decode and not crop and not scale and (type ~= "^(?i:clipboard_png|pdf|url|file|stream|RandomAccessStream|hex|base64)$") @@ -262,25 +240,33 @@ class ImagePut { - static IsImageObject(image) { - if IsObject(image) - for prop in image.OwnProps() - for type in this.ImageTypes - if prop = type - return True - return False - } + static DontVerifyImageType(&image, &keywords := "") { - static DontVerifyImageType(&image) { + ; Sentinel value: Returns the empty string for unknown properties. + keywords := {base: {__get: this.get}} + ; Try ImageType. if !IsObject(image) throw Error("Must be an object.") + ; Goto ImageType. + if ObjHasOwnProp(image, "image") { + keywords := image + keywords.base := {__get: this.get} + image := image.image + throw Error("Must catch this error with ImageType.") + } + + ; Skip ImageType. for type in this.ImageTypes - if ObjHasOwnProp(image, type) - if image := image.%type% - return type + if ObjHasOwnProp(image, type) { + keywords := image + keywords.base := {__get: this.get} + image := image.%type% + return type + } + ; Continue ImageType. throw Error("Invalid type.") } From 1cfc72c091160c443aca1fafc50819f2fd69fd48 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 24 Apr 2022 12:43:47 -0400 Subject: [PATCH 227/492] Sync from_wicBitmap and use IWICBitmapSource --- ImagePut (for v1).ahk | 23 +++++++++++------------ ImagePut.ahk | 43 +++++++++++++++++++++++++++++++++++++------ 2 files changed, 48 insertions(+), 18 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index f128df0b..d3c3d924 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -372,11 +372,11 @@ class ImagePut { try if ComObjQuery(image, "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}") return "RandomAccessStream", ObjRelease(image) - ; A "wicBitmap" is a pointer to the IWICBitmap interface bitmap. - try if ComObjQuery(image, "{00000121-A8F2-4877-BA0A-FD2B6645FB94}") + ; A "wicBitmap" is a pointer to a IWICBitmapSource. + try if ComObjQuery(image, "{00000120-A8F2-4877-BA0A-FD2B6645FB94}") return "wicBitmap", ObjRelease(image) - ; A "d2dBitmap" is a pointer to the ID2D1Bitmap interface bitmap. + ; A "d2dBitmap" is a pointer to a ID2D1Bitmap. try if ComObjQuery(image, "{A2296057-EA42-4099-983B-539FB6505426}") return "d2dBitmap", ObjRelease(image) } @@ -1463,14 +1463,14 @@ class ImagePut { } from_wicBitmap(image) { - ; IWICBitmap::GetSize - https://github.com/tpn/winsdk-10/blob/9b69fd26ac0c7d0b83d378dba01080e93349c2ed/Include/10.0.16299.0/um/wincodec.h#L2207 + ; IWICBitmapSource::GetSize - https://github.com/tpn/winsdk-10/blob/9b69fd26ac0c7d0b83d378dba01080e93349c2ed/Include/10.0.16299.0/um/wincodec.h#L1304 DllCall(NumGet(NumGet(image + 0) + A_PtrSize*3), "ptr", image, "uint*", width:=0, "uint*", height:=0) - ; This is the 32-bit ARGB pBitmap (different from an hBitmap) that will receive the final converted pixels. + ; Intialize an empty pBitmap using managed memory. DllCall("gdiplus\GdipCreateBitmapFromScan0" , "int", width, "int", height, "int", 0, "int", 0x26200A, "ptr", 0, "ptr*", pBitmap:=0) - ; Transfer data from source pBitmap to an hBitmap manually. + ; Create a pixel buffer. VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 NumPut( width, Rect, 8, "uint") ; Width NumPut( height, Rect, 12, "uint") ; Height @@ -1480,15 +1480,14 @@ class ImagePut { , "ptr", &Rect , "uint", 2 ; ImageLockMode.WriteOnly , "int", 0x26200A ; Format32bppArgb - , "ptr", &BitmapData) ; Contains the pointer (pBits) to the hbm. - - stride := NumGet(BitmapData, 8, "int") + , "ptr", &BitmapData) Scan0 := NumGet(BitmapData, 16, "ptr") + stride := NumGet(BitmapData, 8, "int") - ; IWICBitmap::CopyPixels - https://github.com/tpn/winsdk-10/blob/9b69fd26ac0c7d0b83d378dba01080e93349c2ed/Include/10.0.16299.0/um/wincodec.h#L2225 + ; IWICBitmapSource::CopyPixels - https://github.com/tpn/winsdk-10/blob/9b69fd26ac0c7d0b83d378dba01080e93349c2ed/Include/10.0.16299.0/um/wincodec.h#L1322 DllCall(NumGet(NumGet(image + 0) + A_PtrSize*7), "ptr", image, "ptr", &Rect, "uint", stride, "uint", stride * height, "ptr", Scan0) - ; Unlock + ; Write pixels to bitmap. DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", &BitmapData) return pBitmap @@ -1504,7 +1503,7 @@ class ImagePut { DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) - ; Create a read write pixel buffer. + ; Create a pixel buffer. VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 NumPut( width, Rect, 8, "uint") ; Width NumPut( height, Rect, 12, "uint") ; Height diff --git a/ImagePut.ahk b/ImagePut.ahk index 6f5b2387..589091ee 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -142,8 +142,8 @@ ImageEqual(images*) { class ImagePut { - static decode := False ; Forces conversion using a bitmap. The original file encoding will be lost. - static validate := False ; Always copies image data into memory instead of passing references. + static decode := False ; Forces conversion using a bitmap. The original file encoding will be lost. + static validate := False ; Always copies image data into memory instead of passing references. static call(cotype, image, p*) { @@ -372,11 +372,11 @@ class ImagePut { try if ComObjQuery(image, "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}") return "RandomAccessStream" - ; A "wicBitmap" is a pointer to the IWICBitmap interface bitmap. - try if ComObjQuery(image, "{00000121-A8F2-4877-BA0A-FD2B6645FB94}") + ; A "wicBitmap" is a pointer to a IWICBitmapSource. + try if ComObjQuery(image, "{00000120-A8F2-4877-BA0A-FD2B6645FB94}") return "wicBitmap" - ; A "d2dBitmap" is a pointer to the ID2D1Bitmap interface bitmap. + ; A "d2dBitmap" is a pointer to a ID2D1Bitmap. try if ComObjQuery(image, "{A2296057-EA42-4099-983B-539FB6505426}") return "d2dBitmap" } @@ -1462,6 +1462,37 @@ class ImagePut { return pStream } + static from_wicBitmap(image) { + ; IWICBitmapSource::GetSize - https://github.com/tpn/winsdk-10/blob/9b69fd26ac0c7d0b83d378dba01080e93349c2ed/Include/10.0.16299.0/um/wincodec.h#L1304 + ComCall(3, image, "uint*", &width:=0, "uint*", &height:=0) + + ; Intialize an empty pBitmap using managed memory. + DllCall("gdiplus\GdipCreateBitmapFromScan0" + , "int", width, "int", height, "int", 0, "int", 0x26200A, "ptr", 0, "ptr*", &pBitmap:=0) + + ; Create a pixel buffer. + Rect := Buffer(16, 0) ; sizeof(Rect) = 16 + NumPut( "uint", width, Rect, 8) ; Width + NumPut( "uint", height, Rect, 12) ; Height + BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + DllCall("gdiplus\GdipBitmapLockBits" + , "ptr", pBitmap + , "ptr", Rect + , "uint", 2 ; ImageLockMode.WriteOnly + , "int", 0x26200A ; Format32bppArgb + , "ptr", BitmapData) + Scan0 := NumGet(BitmapData, 16, "ptr") + stride := NumGet(BitmapData, 8, "int") + + ; IWICBitmapSource::CopyPixels - https://github.com/tpn/winsdk-10/blob/9b69fd26ac0c7d0b83d378dba01080e93349c2ed/Include/10.0.16299.0/um/wincodec.h#L1322 + ComCall(7, image, "ptr", Rect, "uint", stride, "uint", stride * height, "ptr", Scan0) + + ; Write pixels to bitmap. + DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", BitmapData) + + return pBitmap + } + static from_sprite(image) { ; Create a source pBitmap. if !(pBitmap := this.from_file(image)) @@ -1472,7 +1503,7 @@ class ImagePut { DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) - ; Create a read write pixel buffer. + ; Create a pixel buffer. Rect := Buffer(16, 0) ; sizeof(Rect) = 16 NumPut( "uint", width, Rect, 8) ; Width NumPut( "uint", height, Rect, 12) ; Height From 5510e6f8352930e7616e291a57376aad77f726fd Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 24 Apr 2022 13:02:12 -0400 Subject: [PATCH 228/492] set_clipboard not yet implemented --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index d3c3d924..2b0a3121 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1604,7 +1604,7 @@ class ImagePut { return "" } - set_clipboard(pStream) { + set_clipboard(pStream) { ; Not yet implemented. this.select_extension(pStream, extension:="") if !(extension ~= "gif|png") { diff --git a/ImagePut.ahk b/ImagePut.ahk index 589091ee..9b521a0f 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1604,6 +1604,41 @@ class ImagePut { return ClipboardAll() } + set_clipboard(pStream) { ; Not yet implemented. + this.select_extension(pStream, &extension:="") + + if !(extension ~= "gif|png") { + DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", &pBitmap:=0) + this.put_clipboard(pBitmap) + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + return ClipboardAll() + } + + ; Open the clipboard with exponential backoff. + loop + if DllCall("OpenClipboard", "ptr", A_ScriptHwnd) + break + else + if A_Index < 6 + Sleep (2**(A_Index-1) * 30) + else throw Error("Clipboard could not be opened.") + + ; Requires a valid window handle via OpenClipboard or the next call to OpenClipboard will crash. + DllCall("EmptyClipboard") + + DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "int", False, "ptr*", &pSharedStream:=0, "uint") + DllCall("shlwapi\IStream_Size", "ptr", pStream, "uint64*", &size:=0, "uint") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") + DllCall("shlwapi\IStream_Copy", "ptr", pStream, "ptr", pSharedStream, "uint", size, "uint") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") + + DllCall("ole32\GetHGlobalFromStream", "ptr", pSharedStream, "uint*", &hData:=0, "uint") + ObjRelease(pSharedStream) + DllCall("SetClipboardData", "uint", DllCall("RegisterClipboardFormat", "str", extension, "uint"), "ptr", hData) + DllCall("CloseClipboard") + return ClipboardAll() + } + static put_buffer(pBitmap) { return ImagePut.BitmapBuffer(pBitmap) } From 2f974d4124b0a6bb8dbcc8bf0f99f65c1aa6995a Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 24 Apr 2022 14:10:57 -0400 Subject: [PATCH 229/492] Implement PixelSearch in buffer --- ImagePut (for v1).ahk | 52 +++++++++++++++++------------- ImagePut.ahk | 75 ++++++++++++++++++++++++++++++++++++------- 2 files changed, 92 insertions(+), 35 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 2b0a3121..737427a1 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1648,18 +1648,19 @@ class ImagePut { __New(SourceBitmap) { ImagePut.gdiplusStartup() - ; - + ; Get Bitmap width and height. DllCall("gdiplus\GdipGetImageWidth", "ptr", SourceBitmap, "uint*", width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", SourceBitmap, "uint*", height:=0) + ; Allocate global memory. size := 4 * width * height ptr := DllCall("GlobalAlloc", "uint", 0, "uptr", size, "ptr") + ; Create a pBitmap on saved memory. DllCall("gdiplus\GdipCreateBitmapFromScan0" , "int", width, "int", height, "int", 4 * width, "int", 0x26200A, "ptr", ptr, "ptr*", pBitmap:=0) - ; Transfer data from source pBitmap to an hBitmap manually. + ; Create a pixel buffer. VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 NumPut( width, Rect, 8, "uint") ; Width NumPut( height, Rect, 12, "uint") ; Height @@ -1671,7 +1672,9 @@ class ImagePut { , "ptr", &Rect , "uint", 5 ; ImageLockMode.UserInputBuffer | ImageLockMode.ReadOnly , "int", 0x26200A ; Format32bppArgb - , "ptr", &BitmapData) ; Contains the pointer (pBits) to the hbm. + , "ptr", &BitmapData) + + ; Write pixels to bitmap. DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", SourceBitmap, "ptr", &BitmapData) this.width := width @@ -1683,34 +1686,37 @@ class ImagePut { __Delete() { ImagePut.gdiplusShutdown("smart_pointer", this.pBitmap) + DllCall("GlobalFree", "ptr", this.ptr) } __Get(x, y) { return Format("0x{:X}", NumGet(this.ptr + 4*(y*this.width + x), "uint")) } + Base64Put(code) { + size := StrLen(RTrim(code, "=")) * 3 // 4 + bin := DllCall("GlobalAlloc", "uint", 0, "uptr", size, "ptr") + DllCall("VirtualProtect", "ptr", bin, "ptr", size, "uint", 0x40, "uint*", old:=0) + DllCall("crypt32\CryptStringToBinary", "str", code, "uint", 0, "uint", 0x1, "ptr", bin, "uint*", size, "ptr", 0, "ptr", 0) + return bin + } + PixelSearch(color) { - static bin := 0 - if !bin { - ; C source code - https://godbolt.org/z/rvTWqrqv6 - code := (A_PtrSize == 4) - ? "VYnlU4tFCItVDI0MkDnIcxCLXRA5GHUEicLrBYPABOvsidBbXcM=" - : "idJIjQSRSDnBcw9EOQF1BInI6wZIg8EE6+zD" - padding := (code ~= "==$") ? 2 : (code ~= "=$") ? 1 : 0 - size := 3 * (StrLen(code) / 4) - padding - bin := DllCall("GlobalAlloc", "uint", 0, "uptr", size, "ptr") - DllCall("VirtualProtect", "ptr", bin, "ptr", size, "uint", 0x40, "uint*", old:=0) - DllCall("crypt32\CryptStringToBinary", "str", code, "uint", 0, "uint", 0x1, "ptr", bin, "uint*", size, "ptr", 0, "ptr", 0) - } + ; C source code - https://godbolt.org/z/9v7vzf5az + static bin := 0, code := (A_PtrSize == 4) + ? "VYnli1UMi00Qi0UIOdBzCTkIdAeDwATr84nQXcM=" + : "SInISDnQcwtEOQB0CUiDwATr8EiJ0MM=" + (!bin && bin := this.Base64Put(code)) + + ; Lift color to 32-bits if first 8 bits are zero. + (!(color >> 24) && color |= 0xFF000000) - ; Pass the width * height, but the size is returned due to C interpreting Scan0 as a integer pointer. - ; So when doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. - byte := DllCall(bin, "ptr", this.ptr, "uint", this.width * this.height, "uint", color, "int") + ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. + byte := DllCall(bin, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "int") if (byte == this.ptr + this.size) - throw Exception("pixel not found") - x := mod((byte - this.ptr) / 4, this.width) - y := ((byte - this.ptr) / 4) // this.width - return {x:x, y:y} + return False + offset := (byte - this.ptr) // 4 + return {x: mod(offset, this.width), y: offset // this.width} } } diff --git a/ImagePut.ahk b/ImagePut.ahk index 9b521a0f..5e6e5cfc 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1644,27 +1644,78 @@ class ImagePut { } class BitmapBuffer { - __New(pBitmap) { - this.pBitmap := pBitmap + __New(SourceBitmap) { ImagePut.gdiplusStartup() + + ; Get Bitmap width and height. + DllCall("gdiplus\GdipGetImageWidth", "ptr", SourceBitmap, "uint*", &width:=0) + DllCall("gdiplus\GdipGetImageHeight", "ptr", SourceBitmap, "uint*", &height:=0) + + ; Allocate global memory. + size := 4 * width * height + ptr := DllCall("GlobalAlloc", "uint", 0, "uptr", size, "ptr") + + ; Create a pBitmap on saved memory. + DllCall("gdiplus\GdipCreateBitmapFromScan0" + , "int", width, "int", height, "int", 4 * width, "int", 0x26200A, "ptr", ptr, "ptr*", &pBitmap:=0) + + ; Fill a pixel buffer. + Rect := Buffer(16, 0) ; sizeof(Rect) = 16 + NumPut( "uint", width, Rect, 8) ; Width + NumPut( "uint", height, Rect, 12) ; Height + BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + NumPut( "int", 4 * width, BitmapData, 8) ; Stride + NumPut( "ptr", ptr, BitmapData, 16) ; Scan0 + DllCall("gdiplus\GdipBitmapLockBits" + , "ptr", SourceBitmap + , "ptr", Rect + , "uint", 5 ; ImageLockMode.UserInputBuffer | ImageLockMode.ReadOnly + , "int", 0x26200A ; Format32bppArgb + , "ptr", BitmapData) + + ; Write pixels to bitmap. + DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", SourceBitmap, "ptr", BitmapData) + + this.width := width + this.height := height + this.ptr := ptr + this.size := size + this.pBitmap := pBitmap } __Delete() { ImagePut.gdiplusShutdown("smart_pointer", this.pBitmap) + DllCall("GlobalFree", "ptr", this.ptr) } - width { - get { - DllCall("gdiplus\GdipGetImageWidth", "ptr", this.pBitmap, "uint*", &width:=0) - return width - } + __Get(x, y) { + return Format("0x{:X}", NumGet(this.ptr + 4*(y*this.width + x), "uint")) } - height { - get { - DllCall("gdiplus\GdipGetImageHeight", "ptr", this.pBitmap, "uint*", &height:=0) - return height - } + Base64Put(code) { + size := StrLen(RTrim(code, "=")) * 3 // 4 + bin := DllCall("GlobalAlloc", "uint", 0, "uptr", size, "ptr") + DllCall("VirtualProtect", "ptr", bin, "ptr", size, "uint", 0x40, "uint*", &old:=0) + DllCall("crypt32\CryptStringToBinary", "str", code, "uint", 0, "uint", 0x1, "ptr", bin, "uint*", size, "ptr", 0, "ptr", 0) + return bin + } + + PixelSearch(color) { + ; C source code - https://godbolt.org/z/9v7vzf5az + static bin := 0, code := (A_PtrSize == 4) + ? "VYnli1UMi00Qi0UIOdBzCTkIdAeDwATr84nQXcM=" + : "SInISDnQcwtEOQB0CUiDwATr8EiJ0MM=" + (!bin && bin := this.Base64Put(code)) + + ; Lift color to 32-bits if first 8 bits are zero. + (!(color >> 24) && color |= 0xFF000000) + + ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. + byte := DllCall(bin, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "int") + if (byte == this.ptr + this.size) + return False + offset := (byte - this.ptr) // 4 + return {x: mod(offset, this.width), y: offset // this.width} } } From 7b42da24406dec08ae9ed967b685de51d2fb5b88 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 24 Apr 2022 14:11:49 -0400 Subject: [PATCH 230/492] C source files --- source/colorkey.c | 9 +++++++++ source/pixelsearch.c | 9 +++++++++ 2 files changed, 18 insertions(+) create mode 100644 source/colorkey.c create mode 100644 source/pixelsearch.c diff --git a/source/colorkey.c b/source/colorkey.c new file mode 100644 index 00000000..215bedee --- /dev/null +++ b/source/colorkey.c @@ -0,0 +1,9 @@ +void colorkey(unsigned int * Scan0, unsigned int size, unsigned int key) { + unsigned int * start = Scan0; + unsigned int * end = Scan0 + size; + while (start < end) { + if (*start == key) + *start = 0x00000000; + start++; + } +} \ No newline at end of file diff --git a/source/pixelsearch.c b/source/pixelsearch.c new file mode 100644 index 00000000..fd35134d --- /dev/null +++ b/source/pixelsearch.c @@ -0,0 +1,9 @@ +unsigned int * pixelsearch(unsigned int * start, unsigned int * end, unsigned int color) { + unsigned int * current = start; + while (current < end) { + if (*current == color) + return current; + current++; + } + return end; +} \ No newline at end of file From 64a13e74de4024c3ff46d8bdd8d7c8b06ac50c3c Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 24 Apr 2022 14:27:27 -0400 Subject: [PATCH 231/492] put_wicBitmap --- ImagePut (for v1).ahk | 5 +++++ ImagePut.ahk | 46 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 737427a1..810581eb 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -99,6 +99,11 @@ ImagePutWallpaper(image) { return ImagePut("wallpaper", image) } +; Puts the image into a WICBitmap and returns the pointer to the interface. +ImagePutWICBitmap(image) { + return ImagePut("wicBitmap", image) +} + ; Puts the image in a window and returns a handle to a window. ; title - Window Title | string -> MyTitle ; pos - Window Coordinates | array -> [x,y,w,h] or [0,0] diff --git a/ImagePut.ahk b/ImagePut.ahk index 5e6e5cfc..cd6ed5db 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -99,6 +99,11 @@ ImagePutWallpaper(image) { return ImagePut("wallpaper", image) } +; Puts the image into a WICBitmap and returns the pointer to the interface. +ImagePutWICBitmap(image) { + return ImagePut("wicBitmap", image) +} + ; Puts the image in a window and returns a handle to a window. ; title - Window Title | string -> MyTitle ; pos - Window Coordinates | array -> [x,y,w,h] or [0,0] @@ -1644,6 +1649,7 @@ class ImagePut { } class BitmapBuffer { + __New(SourceBitmap) { ImagePut.gdiplusStartup() @@ -2402,6 +2408,46 @@ class ImagePut { return pRandomAccessStream } + static put_wicBitmap(pBitmap) { + ; Get Bitmap width and height. + DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) + DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) + + ; Initialize Windows Imaging Component. + IWICImagingFactory := ComObject(CLSID_WICImagingFactory := "{CACAF262-9370-4615-A13B-9F5539DA4C0A}", IID_IWICImagingFactory := "{EC5EC8A9-C395-4314-9C77-54D7A935FF70}") + + ; WICBitmapNoCache must be 1! + ; IWICImagingFactory::CreateBitmap - https://github.com/tpn/winsdk-10/blob/9b69fd26ac0c7d0b83d378dba01080e93349c2ed/Include/10.0.16299.0/um/wincodec.h#L6447 + DllCall("ole32\CLSIDFromString", "wstr", GUID_WICPixelFormat32bppBGRA := "{6fddc324-4e03-4bfe-b185-3d77768dc90f}", "ptr", CLSID := Buffer(16), "HRESULT") + ComCall(17, IWICImagingFactory, "uint", width, "uint", height, "ptr", CLSID, "int", 1, "ptr*", &wicBitmap:=0) + + Rect := Buffer(16, 0) ; sizeof(Rect) = 16 + NumPut( "uint", width, Rect, 8) ; Width + NumPut( "uint", height, Rect, 12) ; Height + + ; IWICBitmap::Lock - https://github.com/tpn/winsdk-10/blob/9b69fd26ac0c7d0b83d378dba01080e93349c2ed/Include/10.0.16299.0/um/wincodec.h#L2232 + ComCall(8, wicBitmap, "Ptr", Rect, "uint", 0x1, "ptr*", &Lock:=0) + + ; IWICBitmapLock::GetDataPointer - https://github.com/tpn/winsdk-10/blob/9b69fd26ac0c7d0b83d378dba01080e93349c2ed/Include/10.0.16299.0/um/wincodec.h#L2104 + ComCall(5, Lock, "uint*", &size:=0, "ptr*", &Scan0:=0) + + BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + NumPut( "int", 4 * width, BitmapData, 8) ; Stride + NumPut( "ptr", Scan0, BitmapData, 16) ; Scan0 + DllCall("gdiplus\GdipBitmapLockBits" + , "ptr", pBitmap + , "ptr", Rect + , "uint", 5 ; ImageLockMode.UserInputBuffer | ImageLockMode.ReadOnly + , "int", 0x26200A ; Format32bppArgb + , "ptr", BitmapData) ; Contains the pointer (Scan0) to the WICBitmap. + DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", BitmapData) + + ObjRelease(Lock) + IWICImagingFactory := "" + + return wicBitmap + } + static select_codec(pBitmap, extension, quality, &pCodec, &ep, &ci, &v) { ; Fill a buffer with the available image codec info. DllCall("gdiplus\GdipGetImageEncodersSize", "uint*", &count:=0, "uint*", &size:=0) From acd9d75de0960dd15110b31e103711aa53d4e4eb Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 24 Apr 2022 14:28:51 -0400 Subject: [PATCH 232/492] v1.7 --- ImagePut (for v1).ahk | 4 ++-- ImagePut.ahk | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 810581eb..ae476e3c 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2,8 +2,8 @@ ; License: MIT License ; Author: Edison Hua (iseahound) ; Github: https://github.com/iseahound/ImagePut -; Date: 2022-01-01 -; Version: 1.6.0 +; Date: 2022-04-24 +; Version: 1.7.0 #Requires AutoHotkey v1.1.33+ diff --git a/ImagePut.ahk b/ImagePut.ahk index cd6ed5db..cddfafa4 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2,8 +2,8 @@ ; License: MIT License ; Author: Edison Hua (iseahound) ; Github: https://github.com/iseahound/ImagePut -; Date: 2022-01-01 -; Version: 1.6.0 +; Date: 2022-04-24 +; Version: 1.7.0 #Requires AutoHotkey v2.0-beta.3+ From 026570f55ff73aae1f7685645eb57c9197051259 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 26 Apr 2022 13:47:12 -0400 Subject: [PATCH 233/492] Allow ImagePutScreenshot(img, [0, 0]) small arrays --- ImagePut (for v1).ahk | 8 ++++---- ImagePut.ahk | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index ae476e3c..6857c987 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1730,10 +1730,10 @@ class ImagePut { DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) - x := (IsObject(screenshot) && screenshot[1] != "") ? screenshot[1] : 0 - y := (IsObject(screenshot) && screenshot[2] != "") ? screenshot[2] : 0 - w := (IsObject(screenshot) && screenshot[3] != "") ? screenshot[3] : width - h := (IsObject(screenshot) && screenshot[4] != "") ? screenshot[4] : height + x := IsObject(screenshot) && screenshot.HasKey(1) ? screenshot[1] : 0 + y := IsObject(screenshot) && screenshot.HasKey(2) ? screenshot[2] : 0 + w := IsObject(screenshot) && screenshot.HasKey(3) ? screenshot[3] : width + h := IsObject(screenshot) && screenshot.HasKey(4) ? screenshot[4] : height ; Convert the Bitmap to a hBitmap and associate a device context for blitting. hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") diff --git a/ImagePut.ahk b/ImagePut.ahk index cddfafa4..aec59215 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1730,10 +1730,10 @@ class ImagePut { DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) - x := (IsObject(screenshot) && screenshot[1] != "") ? screenshot[1] : 0 - y := (IsObject(screenshot) && screenshot[2] != "") ? screenshot[2] : 0 - w := (IsObject(screenshot) && screenshot[3] != "") ? screenshot[3] : width - h := (IsObject(screenshot) && screenshot[4] != "") ? screenshot[4] : height + x := IsObject(screenshot) && screenshot.Has(1) ? screenshot[1] : 0 + y := IsObject(screenshot) && screenshot.Has(2) ? screenshot[2] : 0 + w := IsObject(screenshot) && screenshot.Has(3) ? screenshot[3] : width + h := IsObject(screenshot) && screenshot.Has(4) ? screenshot[4] : height ; Convert the Bitmap to a hBitmap and associate a device context for blitting. hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") From 33fa9df9c486d9d679b396bcf940bb78d2739d4d Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 26 Apr 2022 13:56:26 -0400 Subject: [PATCH 234/492] Validate integer parameters in put_cursor --- ImagePut (for v1).ahk | 8 ++++---- ImagePut.ahk | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 6857c987..1eb51ac1 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2146,13 +2146,13 @@ class ImagePut { DllCall("gdiplus\GdipCreateHICONFromBitmap", "ptr", pBitmap, "ptr*", hIcon:=0) ; Sets the hotspot of the cursor by changing the icon into a cursor. - if (xHotspot != "" || yHotspot != "") { + if (xHotspot ~= "^\d+$" || yHotspot ~= "^\d+$") { ; struct ICONINFO - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-iconinfo VarSetCapacity(ii, 8+3*A_PtrSize) ; sizeof(ICONINFO) = 20, 32 DllCall("GetIconInfo", "ptr", hIcon, "ptr", &ii) ; Fill the ICONINFO structure. - NumPut(False, ii, 0, "uint") ; True/false are icon/cursor respectively. - (xHotspot != "") ? NumPut(xHotspot, ii, 4, "uint") : {} ; Set the xHotspot value. (Default: center point) - (yHotspot != "") ? NumPut(yHotspot, ii, 8, "uint") : {} ; Set the yHotspot value. (Default: center point) + NumPut(False, ii, 0, "uint") ; True/False are icon/cursor respectively. + (xHotspot ~= "^\d+$") ? NumPut(xHotspot, ii, 4, "uint") : {} ; Set the xHotspot value. Default: center point + (yHotspot ~= "^\d+$") ? NumPut(yHotspot, ii, 8, "uint") : {} ; Set the yHotspot value. Default: center point DllCall("DestroyIcon", "ptr", hIcon) ; Destroy the icon after getting the ICONINFO structure. hIcon := DllCall("CreateIconIndirect", "ptr", &ii, "ptr") ; Create a new cursor using ICONINFO. diff --git a/ImagePut.ahk b/ImagePut.ahk index aec59215..bd7c5f1f 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2146,13 +2146,13 @@ class ImagePut { DllCall("gdiplus\GdipCreateHICONFromBitmap", "ptr", pBitmap, "ptr*", &hIcon:=0) ; Sets the hotspot of the cursor by changing the icon into a cursor. - if (xHotspot != "" || yHotspot != "") { + if (xHotspot ~= "^\d+$" || yHotspot ~= "^\d+$") { ; struct ICONINFO - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-iconinfo ii := Buffer(8+3*A_PtrSize) ; sizeof(ICONINFO) = 20, 32 DllCall("GetIconInfo", "ptr", hIcon, "ptr", ii) ; Fill the ICONINFO structure. NumPut("uint", False, ii, 0) ; True/False are icon/cursor respectively. - (xHotspot != "") ? NumPut("uint", xHotspot, ii, 4) : {} ; Set the xHotspot value. (Default: center point) - (yHotspot != "") ? NumPut("uint", yHotspot, ii, 8) : {} ; Set the yHotspot value. (Default: center point) + (xHotspot ~= "^\d+$") ? NumPut("uint", xHotspot, ii, 4) : {} ; Set the xHotspot value. Default: center point + (yHotspot ~= "^\d+$") ? NumPut("uint", yHotspot, ii, 8) : {} ; Set the yHotspot value. Default: center point DllCall("DestroyIcon", "ptr", hIcon) ; Destroy the icon after getting the ICONINFO structure. hIcon := DllCall("CreateIconIndirect", "ptr", ii, "ptr") ; Create a new cursor using ICONINFO. From f114728bf07fa73626f44fcb80730dbbabca0d1a Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 26 Apr 2022 16:43:29 -0400 Subject: [PATCH 235/492] Use (!value) && value := foo notation --- ImagePut (for v1).ahk | 12 ++++++------ ImagePut.ahk | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 1eb51ac1..36e4b361 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -397,8 +397,8 @@ class ImagePut { ToBitmap(type, image, k := "") { - ; Sentinel value - k := (k != "") ? k : {base: {__get: this.get}} ; Returns the empty string for unknown properties. + ; Sentinel value: Returns the empty string for unknown properties. + (!k) && k := {base: {__get: this.get}} if (type = "clipboard_png") return this.from_clipboard_png() @@ -554,8 +554,8 @@ class ImagePut { ToStream(type, image, k := "") { - ; Sentinel value - k := (k != "") ? k : {base: {__get: this.get}} ; Returns the empty string for unknown properties. + ; Sentinel value: Returns the empty string for unknown properties. + (!k) && k := {base: {__get: this.get}} if (type = "clipboard_png") return this.get_clipboard_png() @@ -1711,10 +1711,10 @@ class ImagePut { static bin := 0, code := (A_PtrSize == 4) ? "VYnli1UMi00Qi0UIOdBzCTkIdAeDwATr84nQXcM=" : "SInISDnQcwtEOQB0CUiDwATr8EiJ0MM=" - (!bin && bin := this.Base64Put(code)) + (!bin) && bin := this.Base64Put(code) ; Lift color to 32-bits if first 8 bits are zero. - (!(color >> 24) && color |= 0xFF000000) + (!(color >> 24)) && color |= 0xFF000000 ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. byte := DllCall(bin, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "int") diff --git a/ImagePut.ahk b/ImagePut.ahk index bd7c5f1f..1d976064 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -397,8 +397,8 @@ class ImagePut { static ToBitmap(type, image, k := "") { - ; Sentinel value - k := (k != "") ? k : {base: {__get: this.get}} ; Returns the empty string for unknown properties. + ; Sentinel value: Returns the empty string for unknown properties. + (!k) && k := {base: {__get: this.get}} if (type = "clipboard_png") return this.from_clipboard_png() @@ -554,8 +554,8 @@ class ImagePut { static ToStream(type, image, k := "") { - ; Sentinel value - k := (k != "") ? k : {base: {__get: this.get}} ; Returns the empty string for unknown properties. + ; Sentinel value: Returns the empty string for unknown properties. + (!k) && k := {base: {__get: this.get}} if (type = "clipboard_png") return this.get_clipboard_png() @@ -1711,10 +1711,10 @@ class ImagePut { static bin := 0, code := (A_PtrSize == 4) ? "VYnli1UMi00Qi0UIOdBzCTkIdAeDwATr84nQXcM=" : "SInISDnQcwtEOQB0CUiDwATr8EiJ0MM=" - (!bin && bin := this.Base64Put(code)) + (!bin) && bin := this.Base64Put(code) ; Lift color to 32-bits if first 8 bits are zero. - (!(color >> 24) && color |= 0xFF000000) + (!(color >> 24)) && color |= 0xFF000000 ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. byte := DllCall(bin, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "int") From 6fa1f27b3da1a1ebe7b2a425ead3c25c008bc053 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 5 May 2022 13:46:40 -0400 Subject: [PATCH 236/492] C source files --- source/colorkey.c | 6 ++---- source/cpuid.c | 19 ++++++++++++++++++ source/cpuid2.c | 38 ++++++++++++++++++++++++++++++++++++ source/imagesearch.c | 46 ++++++++++++++++++++++++++++++++++++++++++++ source/setalpha.c | 6 ++++++ source/transcolor.c | 7 +++++++ 6 files changed, 118 insertions(+), 4 deletions(-) create mode 100644 source/cpuid.c create mode 100644 source/cpuid2.c create mode 100644 source/imagesearch.c create mode 100644 source/setalpha.c create mode 100644 source/transcolor.c diff --git a/source/colorkey.c b/source/colorkey.c index 215bedee..964966e8 100644 --- a/source/colorkey.c +++ b/source/colorkey.c @@ -1,9 +1,7 @@ -void colorkey(unsigned int * Scan0, unsigned int size, unsigned int key) { - unsigned int * start = Scan0; - unsigned int * end = Scan0 + size; +void colorkey(unsigned int * start, unsigned int * end, unsigned int key, unsigned int value) { while (start < end) { if (*start == key) - *start = 0x00000000; + *start = value; start++; } } \ No newline at end of file diff --git a/source/cpuid.c b/source/cpuid.c new file mode 100644 index 00000000..ca11f3bd --- /dev/null +++ b/source/cpuid.c @@ -0,0 +1,19 @@ +void CPUID(unsigned long * a, unsigned long * b, unsigned long * c, unsigned long * d) +{ + __asm + { + mov eax, DWORD PTR [a] + mov eax, DWORD PTR [eax] + cpuid + push eax + mov eax, DWORD PTR [b] + mov DWORD PTR [eax], ebx + mov eax, DWORD PTR [c] + mov DWORD PTR [eax], ecx + mov eax, DWORD PTR [d] + mov DWORD PTR [eax], edx + pop eax + mov edx, DWORD PTR [a] + mov DWORD PTR [edx], eax + } +} \ No newline at end of file diff --git a/source/cpuid2.c b/source/cpuid2.c new file mode 100644 index 00000000..8edf713d --- /dev/null +++ b/source/cpuid2.c @@ -0,0 +1,38 @@ +static inline void native_cpuid(unsigned int *eax, unsigned int *ebx, + unsigned int *ecx, unsigned int *edx) +{ + /* ecx is often an input as well as an output. */ + asm volatile("cpuid" + : "=a" (*eax), + "=b" (*ebx), + "=c" (*ecx), + "=d" (*edx) + : "0" (*eax), "2" (*ecx)); +} + +#include + +int main(int argc, char **argv) +{ + unsigned eax, ebx, ecx, edx; + + eax = 1; /* processor info and feature bits */ + native_cpuid(&eax, &ebx, &ecx, &edx); + + printf("stepping %d\n", eax & 0xF); + printf("model %d\n", (eax >> 4) & 0xF); + printf("family %d\n", (eax >> 8) & 0xF); + printf("processor type %d\n", (eax >> 12) & 0x3); + printf("extended model %d\n", (eax >> 16) & 0xF); + printf("extended family %d\n", (eax >> 20) & 0xFF); + + /* EDIT */ + eax = 3; /* processor serial number */ + native_cpuid(&eax, &ebx, &ecx, &edx); + + /** see the CPUID Wikipedia article on which models return the serial + number in which registers. The example here is for + Pentium III */ + printf("serial number 0x%08x%08x\n", edx, ecx); + +} \ No newline at end of file diff --git a/source/imagesearch.c b/source/imagesearch.c new file mode 100644 index 00000000..4ce00c8a --- /dev/null +++ b/source/imagesearch.c @@ -0,0 +1,46 @@ +unsigned int * imagesearch(unsigned int * Scan0, unsigned int width, unsigned int height, unsigned int * image, unsigned int w, unsigned int h) { + unsigned int * start = Scan0; + unsigned int * end = Scan0 + width * height; + + // Start off searching with pointers. + while (start < end) { + + int x, y, offset; + int max_w = width - w; + int max_h = height - h; + unsigned int * s; + unsigned int * e; + unsigned int * current; + + // Dereference pointers to check first pixel of subimage. + if (*start == *image) { + // Convert pointer to (x, y). + offset = start - Scan0; + x = offset % width; + y = offset / width; + + // Subimage loop. + current = start; + s = image; + e = image + w; + + // Check if (x, y) exceeds bounds. + if (x < max_w && y < max_h) { + for (int i = 0; i < h; i++) { + while (s < e) { + if (*s != *current) + goto next; + current++; + s++; + } + current += height; + s += h; + } + return start; + } + } + next: + start++; + } + return end; +} \ No newline at end of file diff --git a/source/setalpha.c b/source/setalpha.c new file mode 100644 index 00000000..69ac4c33 --- /dev/null +++ b/source/setalpha.c @@ -0,0 +1,6 @@ +void setalpha(unsigned int * start, unsigned int * end, unsigned char alpha) { + while (start < end) { + *((char *) start + 3) = alpha; + start++; + } +} \ No newline at end of file diff --git a/source/transcolor.c b/source/transcolor.c new file mode 100644 index 00000000..d7fae951 --- /dev/null +++ b/source/transcolor.c @@ -0,0 +1,7 @@ +void transcolor(unsigned int * start, unsigned int * end, unsigned int color, unsigned char alpha) { + while (start < end) { + if ((*start & 0xFFFFFF) == (color & 0xFFFFFF)) + *((char *) start + 3) = alpha; + start++; + } +} \ No newline at end of file From 33594271074a420dfcd9cad21448cd004c0fdd58 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 5 May 2022 13:47:56 -0400 Subject: [PATCH 237/492] Add Colorkey, SetAlpha, TransColor, ImageSearch --- ImagePut (for v1).ahk | 72 +++++++++++++++++++++++++++++++++++++++++++ ImagePut.ahk | 72 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 36e4b361..9a108b17 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1706,6 +1706,54 @@ class ImagePut { return bin } + CPUID() { + ; C source code - https://godbolt.org/z/9v7vzf5az + static bin := 0, code := (A_PtrSize == 4) + ? "VYnlV4t9EFaLdQhTiw+LBg+iiQaLRQyJGItFFIkPiRBbXl9dww==" + : "U4sBSYnKSYnTQYsID6JBiQJBiRtBiQhBiRFbww==" + (!bin) && bin := this.Base64Put(code) + + ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. + byte := DllCall(bin, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color:=0, "int") + if (byte == this.ptr + this.size) + return False + offset := (byte - this.ptr) // 4 + return {x: mod(offset, this.width), y: offset // this.width} + } + + ColorKey(key := 0xFFFFFFFF, value := 0x00000000) { + ; C source code - https://godbolt.org/z/eaG9fax9v + static bin := 0, code := (A_PtrSize == 4) + ? "VYnli0UIi1UQi00UO0UMcws5EHUCiQiDwATr8F3D" + : "SDnRcw5EOQF1A0SJCUiDwQTr7cM=" + (!bin) && bin := this.Base64Put(code) + + ; Replaces one ARGB color with another. + DllCall(bin, "ptr", this.ptr, "uint", this.ptr + this.size, "uint", key, "uint", value) + } + + SetAlpha(alpha := 0xFF) { + ; C source code - https://godbolt.org/z/6e1oYqxnW + static bin := 0, code := (A_PtrSize == 4) + ? "VYnli0UIilUQO0UMcwiIUAODwATr813D" + : "SDnRcwpEiEEDSIPBBOvxww==" + (!bin) && bin := this.Base64Put(code) + + ; Sets the transparency of the entire bitmap. + DllCall(bin, "ptr", this.ptr, "ptr", this.ptr + this.size, "uchar", alpha) + } + + TransColor(color := 0xFFFFFF, alpha := 0x00) { + ; C source code - https://godbolt.org/z/6Wfd61qYE + static bin := 0, code := (A_PtrSize == 4) + ? "VYnli0UIilUUO0UMcxWLTRAzCIHh////AHUDiFADg8AE6+Zdww==" + : "SDnRcxaLAUQxwKn///8AdQREiEkDSIPBBOvlww==" + (!bin) && bin := this.Base64Put(code) + + ; Sets the alpha value of a specified RGB color. + DllCall(bin, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "uchar", alpha) + } + PixelSearch(color) { ; C source code - https://godbolt.org/z/9v7vzf5az static bin := 0, code := (A_PtrSize == 4) @@ -1723,6 +1771,30 @@ class ImagePut { offset := (byte - this.ptr) // 4 return {x: mod(offset, this.width), y: offset // this.width} } + + ImageSearch(image) { + ; C source code - https://godbolt.org/z/q1rxvx38Y + static bin := 0, code := (A_PtrSize == 4) + ? "VYnlV1ZTg+wUi1UYi3UUi0UQi30MjTSWi00MiXXoi3UcjRyFAAAAACnXK0UcD6/LA00IiX3kweYCiUXgiXXsiU3wi00IO03wc0yL" + . "RRSLADkBdT6JyCtFCDHSwfgC93UMOVXkfiw5ReB+J4tFFInKMf87fRx0IztF6HMOizI5MHUQg8IEg8AE6+0B2gNF7Efr4IPBBOuv" + . "i03wg8QUichbXl9dww==" + : "QVdBVkFVQVRVV1ZTi0QkaIt0JHBIifdIweYCSYnLidFEicNBD6/QQYnNSMHjAk2J2kEpxUEp+EmNLJOJwk2NJJFJOepzVkGLAUE5" + . "AnVITInQMdJMKdhIwfgC9/FBOdV+NUE5wH4wTInSTInIRTH2QTn+dCtMOeBzEkSLOkQ5OHUVSIPCBEiDwATr6UgB2kgB8EH/xuvZ" + . "SYPCBOulSYnqTInQW15fXUFcQV1BXkFfww==" + (!bin) && bin := this.Base64Put(code) + + if ImagePut.ImageType(image) != "buffer" + image := ImagePutBuffer(image) + + ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. + byte := DllCall(bin, "ptr", this.ptr, "uint", this.width, "uint", this.height + , "ptr", image.ptr, "uint", image.width, "uint", image.height, "int") + + if (byte == this.ptr + this.size) + return False + offset := (byte - this.ptr) // 4 + return {x: mod(offset, this.width), y: offset // this.width} + } } put_screenshot(pBitmap, screenshot := "", alpha := "") { diff --git a/ImagePut.ahk b/ImagePut.ahk index 1d976064..8c9a7021 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1706,6 +1706,54 @@ class ImagePut { return bin } + CPUID() { + ; C source code - https://godbolt.org/z/9v7vzf5az + static bin := 0, code := (A_PtrSize == 4) + ? "VYnlV4t9EFaLdQhTiw+LBg+iiQaLRQyJGItFFIkPiRBbXl9dww==" + : "U4sBSYnKSYnTQYsID6JBiQJBiRtBiQhBiRFbww==" + (!bin) && bin := this.Base64Put(code) + + ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. + byte := DllCall(bin, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color:=0, "int") + if (byte == this.ptr + this.size) + return False + offset := (byte - this.ptr) // 4 + return {x: mod(offset, this.width), y: offset // this.width} + } + + ColorKey(key := 0xFFFFFFFF, value := 0x00000000) { + ; C source code - https://godbolt.org/z/eaG9fax9v + static bin := 0, code := (A_PtrSize == 4) + ? "VYnli0UIi1UQi00UO0UMcws5EHUCiQiDwATr8F3D" + : "SDnRcw5EOQF1A0SJCUiDwQTr7cM=" + (!bin) && bin := this.Base64Put(code) + + ; Replaces one ARGB color with another. + DllCall(bin, "ptr", this.ptr, "uint", this.ptr + this.size, "uint", key, "uint", value) + } + + SetAlpha(alpha := 0xFF) { + ; C source code - https://godbolt.org/z/6e1oYqxnW + static bin := 0, code := (A_PtrSize == 4) + ? "VYnli0UIilUQO0UMcwiIUAODwATr813D" + : "SDnRcwpEiEEDSIPBBOvxww==" + (!bin) && bin := this.Base64Put(code) + + ; Sets the transparency of the entire bitmap. + DllCall(bin, "ptr", this.ptr, "ptr", this.ptr + this.size, "uchar", alpha) + } + + TransColor(color := 0xFFFFFF, alpha := 0x00) { + ; C source code - https://godbolt.org/z/6Wfd61qYE + static bin := 0, code := (A_PtrSize == 4) + ? "VYnli0UIilUUO0UMcxWLTRAzCIHh////AHUDiFADg8AE6+Zdww==" + : "SDnRcxaLAUQxwKn///8AdQREiEkDSIPBBOvlww==" + (!bin) && bin := this.Base64Put(code) + + ; Sets the alpha value of a specified RGB color. + DllCall(bin, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "uchar", alpha) + } + PixelSearch(color) { ; C source code - https://godbolt.org/z/9v7vzf5az static bin := 0, code := (A_PtrSize == 4) @@ -1723,6 +1771,30 @@ class ImagePut { offset := (byte - this.ptr) // 4 return {x: mod(offset, this.width), y: offset // this.width} } + + ImageSearch(image) { + ; C source code - https://godbolt.org/z/q1rxvx38Y + static bin := 0, code := (A_PtrSize == 4) + ? "VYnlV1ZTg+wUi1UYi3UUi0UQi30MjTSWi00MiXXoi3UcjRyFAAAAACnXK0UcD6/LA00IiX3kweYCiUXgiXXsiU3wi00IO03wc0yL" + . "RRSLADkBdT6JyCtFCDHSwfgC93UMOVXkfiw5ReB+J4tFFInKMf87fRx0IztF6HMOizI5MHUQg8IEg8AE6+0B2gNF7Efr4IPBBOuv" + . "i03wg8QUichbXl9dww==" + : "QVdBVkFVQVRVV1ZTi0QkaIt0JHBIifdIweYCSYnLidFEicNBD6/QQYnNSMHjAk2J2kEpxUEp+EmNLJOJwk2NJJFJOepzVkGLAUE5" + . "AnVITInQMdJMKdhIwfgC9/FBOdV+NUE5wH4wTInSTInIRTH2QTn+dCtMOeBzEkSLOkQ5OHUVSIPCBEiDwATr6UgB2kgB8EH/xuvZ" + . "SYPCBOulSYnqTInQW15fXUFcQV1BXkFfww==" + (!bin) && bin := this.Base64Put(code) + + if ImagePut.ImageType(image) != "buffer" + image := ImagePutBuffer(image) + + ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. + byte := DllCall(bin, "ptr", this.ptr, "uint", this.width, "uint", this.height + , "ptr", image.ptr, "uint", image.width, "uint", image.height, "int") + + if (byte == this.ptr + this.size) + return False + offset := (byte - this.ptr) // 4 + return {x: mod(offset, this.width), y: offset // this.width} + } } static put_screenshot(pBitmap, screenshot := "", alpha := "") { From a4bf3bf0b78e240f17b458045f132f7fbac7ce8f Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 5 May 2022 14:02:11 -0400 Subject: [PATCH 238/492] Return an array instead of an object --- ImagePut (for v1).ahk | 6 +++--- ImagePut.ahk | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 9a108b17..459b3ff6 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1718,7 +1718,7 @@ class ImagePut { if (byte == this.ptr + this.size) return False offset := (byte - this.ptr) // 4 - return {x: mod(offset, this.width), y: offset // this.width} + return [mod(offset, this.width), offset // this.width] } ColorKey(key := 0xFFFFFFFF, value := 0x00000000) { @@ -1769,7 +1769,7 @@ class ImagePut { if (byte == this.ptr + this.size) return False offset := (byte - this.ptr) // 4 - return {x: mod(offset, this.width), y: offset // this.width} + return [mod(offset, this.width), offset // this.width] } ImageSearch(image) { @@ -1793,7 +1793,7 @@ class ImagePut { if (byte == this.ptr + this.size) return False offset := (byte - this.ptr) // 4 - return {x: mod(offset, this.width), y: offset // this.width} + return [mod(offset, this.width), offset // this.width] } } diff --git a/ImagePut.ahk b/ImagePut.ahk index 8c9a7021..f24adf07 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1718,7 +1718,7 @@ class ImagePut { if (byte == this.ptr + this.size) return False offset := (byte - this.ptr) // 4 - return {x: mod(offset, this.width), y: offset // this.width} + return [mod(offset, this.width), offset // this.width] } ColorKey(key := 0xFFFFFFFF, value := 0x00000000) { @@ -1769,7 +1769,7 @@ class ImagePut { if (byte == this.ptr + this.size) return False offset := (byte - this.ptr) // 4 - return {x: mod(offset, this.width), y: offset // this.width} + return [mod(offset, this.width), offset // this.width] } ImageSearch(image) { @@ -1793,7 +1793,7 @@ class ImagePut { if (byte == this.ptr + this.size) return False offset := (byte - this.ptr) // 4 - return {x: mod(offset, this.width), y: offset // this.width} + return [mod(offset, this.width), offset // this.width] } } From 2aab700378fde571ecc814883bdaae5cba07171d Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 6 May 2022 09:48:32 -0400 Subject: [PATCH 239/492] comment --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 459b3ff6..5640087b 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1340,7 +1340,7 @@ class ImagePut { DllCall("gdi32\BitBlt" , "ptr", hdc, "int", 0, "int", 0, "int", width, "int", height , "ptr", sdc, "int", 0, "int", 0, "uint", 0x00CC0020) ; SRCCOPY - else + else ; If already selected onto a device context... DllCall("GetDIBits", "ptr", hdc, "ptr", image, "uint", 0, "uint", height, "ptr", pBits, "ptr", &bi, "uint", 0) ; The stock bitmap (obm) can never be leaked. diff --git a/ImagePut.ahk b/ImagePut.ahk index f24adf07..62df8a51 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1340,7 +1340,7 @@ class ImagePut { DllCall("gdi32\BitBlt" , "ptr", hdc, "int", 0, "int", 0, "int", width, "int", height , "ptr", sdc, "int", 0, "int", 0, "uint", 0x00CC0020) ; SRCCOPY - else + else ; If already selected onto a device context... DllCall("GetDIBits", "ptr", hdc, "ptr", image, "uint", 0, "uint", height, "ptr", pBits, "ptr", bi, "uint", 0) ; The stock bitmap (obm) can never be leaked. From 06378da0e8b769c5902ebe4b411cbf54689e1264 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 6 May 2022 13:44:40 -0400 Subject: [PATCH 240/492] Add ImagePutURI --- ImagePut (for v1).ahk | 61 +++++++++++++++++++++++++++++++++++++------ ImagePut.ahk | 61 +++++++++++++++++++++++++++++++++++++------ 2 files changed, 106 insertions(+), 16 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 5640087b..f7973076 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -94,6 +94,13 @@ ImagePutStream(image, extension := "", quality := "") { return ImagePut("stream", image, extension, quality) } +; Puts the image into a file format and returns a URI string. +; extension - File Encoding | string -> bmp, gif, jpg, png, tiff +; quality - JPEG Quality Level | integer -> 0 - 100 +ImagePutURI(image, extension := "", quality := "") { + return ImagePut("uri", image, extension, quality) +} + ; Puts the image as the desktop wallpaper and returns the string "wallpaper". ImagePutWallpaper(image) { return ImagePut("wallpaper", image) @@ -168,7 +175,7 @@ class ImagePut { ; #1 - Stream intermediate. if not decode and not crop and not scale and (type ~= "^(?i:clipboard_png|pdf|url|file|stream|RandomAccessStream|hex|base64)$") - and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64)$") + and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64|uri)$") and (p[1] == "") { ; For now, disallow any specification of extensions. ; Convert via stream intermediate. @@ -521,6 +528,10 @@ class ImagePut { if (cotype = "base64") return this.put_base64(pBitmap, p1, p2) + ; BitmapToCoimage("uri", pBitmap, extension, quality) + if (cotype = "uri") + return this.put_uri(pBitmap, p1, p2) + ; BitmapToCoimage("dc", pBitmap, alpha) if (cotype = "dc") return this.put_dc(pBitmap, p1) @@ -597,6 +608,10 @@ class ImagePut { if (cotype = "base64") return this.set_base64(pStream) + ; StreamToCoimage("uri", pStream) + if (cotype = "uri") + return this.set_uri(pStream) + ; StreamToCoimage("stream", pStream) if (cotype = "stream") return pStream @@ -2387,6 +2402,37 @@ class ImagePut { return StrGet(&str, length, "CP0") } + put_uri(pBitmap, extension := "", quality := "") { + static dict := { bmp: "bmp", dib: "bmp", rle: "bmp", jpg: "jpeg", jpeg: "jpeg", jpe: "jpeg" + , jfif: "jpeg", gif: "gif", tif: "tiff", tiff: "tiff", png: "png" } + + extension := RegExReplace(extension, "^\*?\.?") + return "data:image/" dict[extension] ";base64," this.put_base64(pBitmap, extension, quality) + } + + set_uri(pStream) { + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") + DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", &signature := VarSetCapacity(signature, 256), "uint", 256, "uint") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") + + ; This function sniffs the first 256 bytes and matches a known file signature. + ; 256 bytes is recommended, but images only need 12 bytes. + ; See: https://en.wikipedia.org/wiki/List_of_file_signatures + DllCall("urlmon\FindMimeFromData" + , "ptr", 0 ; pBC + , "ptr", 0 ; pwzUrl + , "ptr", &signature ; pBuffer + , "uint", 256 ; cbSize + , "ptr", 0 ; pwzMimeProposed + , "uint", 0x20 ; dwMimeFlags + , "ptr*", MimeType:=0 ; ppwzMimeOut + , "uint", 0 ; dwReserved + , "uint") + + ; The output is a pointer, that is dereferenced to a Mime string. + return "data:" StrGet(MimeType, "UTF-16") ";base64," this.set_base64(pStream) + } + put_dc(pBitmap, alpha := "") { ; This may seem strange, but the hBitmap is selected onto the device context, ; and therefore cannot be deleted. In addition, the stock bitmap can never be leaked. @@ -2572,7 +2618,7 @@ class ImagePut { , "uint", 0 ; dwReserved , "uint") - ; The output is a pointer to a Mime string. It must be dereferenced. + ; The output is a pointer, that is dereferenced to a Mime string. MimeType := StrGet(MimeType, "UTF-16") if (MimeType ~= "gif") @@ -2591,11 +2637,10 @@ class ImagePut { ; Save default extension. default := extension - ; Convert forward style slashes into Windows style backslashes. + ; Split the filepath, convert forward slashes, strip invalid chars. filepath := RegExReplace(filepath, "/", "\") - - ; Split the filepath. - SplitPath % Trim(filepath),, directory, extension, filename + filepath := RegExReplace(filepath, "[:*?\x22<>|\x00-\x1F]") + SplitPath % filepath,, directory, extension, filename ; Check if the entire filepath is a directory. if InStr(FileExist(filepath), "D") ; If the filepath refers to a directory, @@ -2633,14 +2678,14 @@ class ImagePut { if (filename == "") { FormatTime, filename,, % "yyyy-MM-dd HH?mm?ss" filepath := directory "\" filename "." extension - while FileExist(filepath) ; Check for collisions. + while FileExist(filepath) filepath := directory "\" filename " (" A_Index ")." extension } ; Create a numeric sequence of files... else if (filename == "0" or filename == "1") { filepath := directory "\" filename "." extension - while FileExist(filepath) ; Check for collisions. + while FileExist(filepath) filepath := directory "\" A_Index "." extension } diff --git a/ImagePut.ahk b/ImagePut.ahk index 62df8a51..e3ead457 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -94,6 +94,13 @@ ImagePutStream(image, extension := "", quality := "") { return ImagePut("stream", image, extension, quality) } +; Puts the image into a file format and returns a URI string. +; extension - File Encoding | string -> bmp, gif, jpg, png, tiff +; quality - JPEG Quality Level | integer -> 0 - 100 +ImagePutURI(image, extension := "", quality := "") { + return ImagePut("uri", image, extension, quality) +} + ; Puts the image as the desktop wallpaper and returns the string "wallpaper". ImagePutWallpaper(image) { return ImagePut("wallpaper", image) @@ -168,7 +175,7 @@ class ImagePut { ; #1 - Stream intermediate. if not decode and not crop and not scale and (type ~= "^(?i:clipboard_png|pdf|url|file|stream|RandomAccessStream|hex|base64)$") - and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64)$") + and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64|uri)$") and (!p.Has(1) || p[1] == "") { ; For now, disallow any specification of extensions. ; Convert via stream intermediate. @@ -521,6 +528,10 @@ class ImagePut { if (cotype = "base64") return this.put_base64(pBitmap, p1, p2) + ; BitmapToCoimage("uri", pBitmap, extension, quality) + if (cotype = "uri") + return this.put_uri(pBitmap, p1, p2) + ; BitmapToCoimage("dc", pBitmap, alpha) if (cotype = "dc") return this.put_dc(pBitmap, p1) @@ -597,6 +608,10 @@ class ImagePut { if (cotype = "base64") return this.set_base64(pStream) + ; StreamToCoimage("uri", pStream) + if (cotype = "uri") + return this.set_uri(pStream) + ; StreamToCoimage("stream", pStream) if (cotype = "stream") return pStream @@ -2387,6 +2402,37 @@ class ImagePut { return StrGet(str, length, "CP0") } + static put_uri(pBitmap, extension := "", quality := "") { + static dict := Map("bmp", "bmp", "dib", "bmp", "rle", "bmp", "jpg", "jpeg", "jpeg", "jpeg", "jpe", "jpeg" + , "jfif", "jpeg", "gif", "gif", "tif", "tiff", "tiff", "tiff", "png", "png") + + extension := RegExReplace(extension, "^\*?\.?") + return "data:image/" dict[StrLower(extension)] ";base64," this.put_base64(pBitmap, extension, quality) + } + + static set_uri(pStream) { + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") + DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", signature := Buffer(256), "uint", 256, "HRESULT") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") + + ; This function sniffs the first 256 bytes and matches a known file signature. + ; 256 bytes is recommended, but images only need 12 bytes. + ; See: https://en.wikipedia.org/wiki/List_of_file_signatures + DllCall("urlmon\FindMimeFromData" + , "ptr", 0 ; pBC + , "ptr", 0 ; pwzUrl + , "ptr", signature ; pBuffer + , "uint", 256 ; cbSize + , "ptr", 0 ; pwzMimeProposed + , "uint", 0x20 ; dwMimeFlags + , "ptr*", &MimeType:=0 ; ppwzMimeOut + , "uint", 0 ; dwReserved + ,"HRESULT") + + ; The output is a pointer, that is dereferenced to a Mime string. + return "data:" StrGet(MimeType, "UTF-16") ";base64," this.set_base64(pStream) + } + static put_dc(pBitmap, alpha := "") { ; This may seem strange, but the hBitmap is selected onto the device context, ; and therefore cannot be deleted. In addition, the stock bitmap can never be leaked. @@ -2572,7 +2618,7 @@ class ImagePut { , "uint", 0 ; dwReserved ,"HRESULT") - ; The output is a pointer to a Mime string. It must be dereferenced. + ; The output is a pointer, that is dereferenced to a Mime string. MimeType := StrGet(MimeType, "UTF-16") if (MimeType ~= "gif") @@ -2591,11 +2637,10 @@ class ImagePut { ; Save default extension. default := extension - ; Convert forward style slashes into Windows style backslashes. + ; Split the filepath, convert forward slashes, strip invalid chars. filepath := RegExReplace(filepath, "/", "\") - - ; Split the filepath. - SplitPath Trim(filepath),, &directory, &extension, &filename + filepath := RegExReplace(filepath, "[:*?\x22<>|\x00-\x1F]") + SplitPath filepath,, &directory, &extension, &filename ; Check if the entire filepath is a directory. if DirExist(filepath) ; If the filepath refers to a directory, @@ -2633,14 +2678,14 @@ class ImagePut { if (filename == "") { filename := FormatTime(, "yyyy-MM-dd HH?mm?ss") filepath := directory "\" filename "." extension - while FileExist(filepath) ; Check for collisions. + while FileExist(filepath) filepath := directory "\" filename " (" A_Index ")." extension } ; Create a numeric sequence of files... else if (filename == "0" or filename == "1") { filepath := directory "\" filename "." extension - while FileExist(filepath) ; Check for collisions. + while FileExist(filepath) filepath := directory "\" A_Index "." extension } From 81b9083b065df8f29bb7a730200bc569342cac89 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 6 May 2022 14:13:31 -0400 Subject: [PATCH 241/492] CoTaskMemFree memory patch --- ImagePut (for v1).ahk | 10 +++++----- ImagePut.ahk | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index f7973076..2b549ca9 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2425,12 +2425,13 @@ class ImagePut { , "uint", 256 ; cbSize , "ptr", 0 ; pwzMimeProposed , "uint", 0x20 ; dwMimeFlags - , "ptr*", MimeType:=0 ; ppwzMimeOut + , "ptr*", MimeOut:=0 ; ppwzMimeOut , "uint", 0 ; dwReserved , "uint") + MimeType := StrGet(MimeType, "UTF-16") + DllCall("ole32\CoTaskMemFree", "ptr", MimeOut) - ; The output is a pointer, that is dereferenced to a Mime string. - return "data:" StrGet(MimeType, "UTF-16") ";base64," this.set_base64(pStream) + return "data:" MimeType ";base64," this.set_base64(pStream) } put_dc(pBitmap, alpha := "") { @@ -2617,9 +2618,8 @@ class ImagePut { , "ptr*", MimeType:=0 ; ppwzMimeOut , "uint", 0 ; dwReserved , "uint") - - ; The output is a pointer, that is dereferenced to a Mime string. MimeType := StrGet(MimeType, "UTF-16") + DllCall("ole32\CoTaskMemFree", "ptr", MimeOut) if (MimeType ~= "gif") extension := "gif" diff --git a/ImagePut.ahk b/ImagePut.ahk index e3ead457..46a7c8e1 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2428,9 +2428,10 @@ class ImagePut { , "ptr*", &MimeType:=0 ; ppwzMimeOut , "uint", 0 ; dwReserved ,"HRESULT") + MimeType := StrGet(MimeType, "UTF-16") + DllCall("ole32\CoTaskMemFree", "ptr", MimeOut) - ; The output is a pointer, that is dereferenced to a Mime string. - return "data:" StrGet(MimeType, "UTF-16") ";base64," this.set_base64(pStream) + return "data:" MimeType ";base64," this.set_base64(pStream) } static put_dc(pBitmap, alpha := "") { @@ -2617,9 +2618,8 @@ class ImagePut { , "ptr*", &MimeType:=0 ; ppwzMimeOut , "uint", 0 ; dwReserved ,"HRESULT") - - ; The output is a pointer, that is dereferenced to a Mime string. MimeType := StrGet(MimeType, "UTF-16") + DllCall("ole32\CoTaskMemFree", "ptr", MimeOut) if (MimeType ~= "gif") extension := "gif" From 5193ec2739976fd02f0d94ff0c73f3ca6bbf240c Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 6 May 2022 14:15:12 -0400 Subject: [PATCH 242/492] CoTaskMemFree memory leak patched 2 --- ImagePut (for v1).ahk | 4 ++-- ImagePut.ahk | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 2b549ca9..85cb1af0 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2425,7 +2425,7 @@ class ImagePut { , "uint", 256 ; cbSize , "ptr", 0 ; pwzMimeProposed , "uint", 0x20 ; dwMimeFlags - , "ptr*", MimeOut:=0 ; ppwzMimeOut + , "ptr*", MimeOut:=0 ; ppwzMimeOut , "uint", 0 ; dwReserved , "uint") MimeType := StrGet(MimeType, "UTF-16") @@ -2615,7 +2615,7 @@ class ImagePut { , "uint", 256 ; cbSize , "ptr", 0 ; pwzMimeProposed , "uint", 0x20 ; dwMimeFlags - , "ptr*", MimeType:=0 ; ppwzMimeOut + , "ptr*", MimeOut:=0 ; ppwzMimeOut , "uint", 0 ; dwReserved , "uint") MimeType := StrGet(MimeType, "UTF-16") diff --git a/ImagePut.ahk b/ImagePut.ahk index 46a7c8e1..6a9b3772 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2425,7 +2425,7 @@ class ImagePut { , "uint", 256 ; cbSize , "ptr", 0 ; pwzMimeProposed , "uint", 0x20 ; dwMimeFlags - , "ptr*", &MimeType:=0 ; ppwzMimeOut + , "ptr*", &MimeOut:=0 ; ppwzMimeOut , "uint", 0 ; dwReserved ,"HRESULT") MimeType := StrGet(MimeType, "UTF-16") @@ -2615,7 +2615,7 @@ class ImagePut { , "uint", 256 ; cbSize , "ptr", 0 ; pwzMimeProposed , "uint", 0x20 ; dwMimeFlags - , "ptr*", &MimeType:=0 ; ppwzMimeOut + , "ptr*", &MimeOut:=0 ; ppwzMimeOut , "uint", 0 ; dwReserved ,"HRESULT") MimeType := StrGet(MimeType, "UTF-16") From 9081319c33f9a5a3bb314f3f93b3ad1d9a6be6ce Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 8 May 2022 11:59:52 -0400 Subject: [PATCH 243/492] comment --- ImagePut (for v1).ahk | 8 ++++---- ImagePut.ahk | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 85cb1af0..bae5c0bb 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2323,7 +2323,7 @@ class ImagePut { length := 2 * size + 1 ; An extra byte of padding is required. VarSetCapacity(str, length) - ; Using CryptBinaryToStringA saves about 2MB in memory. + ; Using CryptBinaryToStringA is faster and saves about 2MB in memory. DllCall("crypt32\CryptBinaryToStringA", "ptr", bin, "uint", size, "uint", flags, "ptr", &str, "uint*", length) ; Release binary data and stream. @@ -2346,7 +2346,7 @@ class ImagePut { length := 2 * size + 1 ; An extra byte of padding is required. VarSetCapacity(str, length) - ; Using CryptBinaryToStringA saves about 2MB in memory. + ; Using CryptBinaryToStringA is faster and saves about 2MB in memory. DllCall("crypt32\CryptBinaryToStringA", "ptr", &bin, "uint", size, "uint", flags, "ptr", &str, "uint*", length) ; Return encoded string length minus 1. @@ -2372,7 +2372,7 @@ class ImagePut { length := 4 * Ceil(size/3) + 1 ; An extra byte of padding is required. VarSetCapacity(str, length) - ; Using CryptBinaryToStringA saves about 2MB in memory. + ; Using CryptBinaryToStringA is faster and saves about 2MB in memory. DllCall("crypt32\CryptBinaryToStringA", "ptr", bin, "uint", size, "uint", flags, "ptr", &str, "uint*", length) ; Release binary data and stream. @@ -2395,7 +2395,7 @@ class ImagePut { length := 4 * Ceil(size/3) + 1 ; An extra byte of padding is required. VarSetCapacity(str, length) - ; Using CryptBinaryToStringA saves about 2MB in memory. + ; Using CryptBinaryToStringA is faster and saves about 2MB in memory. DllCall("crypt32\CryptBinaryToStringA", "ptr", &bin, "uint", size, "uint", flags, "ptr", &str, "uint*", length) ; Return encoded string length minus 1. diff --git a/ImagePut.ahk b/ImagePut.ahk index 6a9b3772..6ff9ed46 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2323,7 +2323,7 @@ class ImagePut { length := 2 * size + 1 ; An extra byte of padding is required. str := Buffer(length) - ; Using CryptBinaryToStringA saves about 2MB in memory. + ; Using CryptBinaryToStringA is faster and saves about 2MB in memory. DllCall("crypt32\CryptBinaryToStringA", "ptr", bin, "uint", size, "uint", flags, "ptr", str, "uint*", &length) ; Release binary data and stream. @@ -2346,7 +2346,7 @@ class ImagePut { length := 2 * size + 1 ; An extra byte of padding is required. str := Buffer(length) - ; Using CryptBinaryToStringA saves about 2MB in memory. + ; Using CryptBinaryToStringA is faster and saves about 2MB in memory. DllCall("crypt32\CryptBinaryToStringA", "ptr", bin, "uint", size, "uint", flags, "ptr", str, "uint*", &length) ; Return encoded string length minus 1. @@ -2372,7 +2372,7 @@ class ImagePut { length := 4 * Ceil(size/3) + 1 ; An extra byte of padding is required. str := Buffer(length) - ; Using CryptBinaryToStringA saves about 2MB in memory. + ; Using CryptBinaryToStringA is faster and saves about 2MB in memory. DllCall("crypt32\CryptBinaryToStringA", "ptr", bin, "uint", size, "uint", flags, "ptr", str, "uint*", &length) ; Release binary data and stream. @@ -2395,7 +2395,7 @@ class ImagePut { length := 4 * Ceil(size/3) + 1 ; An extra byte of padding is required. str := Buffer(length) - ; Using CryptBinaryToStringA saves about 2MB in memory. + ; Using CryptBinaryToStringA is faster and saves about 2MB in memory. DllCall("crypt32\CryptBinaryToStringA", "ptr", bin, "uint", size, "uint", flags, "ptr", str, "uint*", &length) ; Return encoded string length minus 1. From cbd90298f541ed2c436e41f801d3218f77d2cbbb Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 8 May 2022 20:18:36 -0400 Subject: [PATCH 244/492] ImageDestroy(wicBitmap) --- ImagePut (for v1).ahk | 3 +++ ImagePut.ahk | 3 +++ 2 files changed, 6 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index bae5c0bb..80a187e3 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2820,6 +2820,9 @@ class ImagePut { if (type = "RandomAccessStream") or (type = "stream") return !ObjRelease(image) + + if (type = "wicBitmap") + return ObjRelease(image) } } ; End of Destroy class. } ; End of ImagePut class. diff --git a/ImagePut.ahk b/ImagePut.ahk index 6ff9ed46..d9439603 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2820,6 +2820,9 @@ class ImagePut { if (type = "RandomAccessStream") or (type = "stream") return !ObjRelease(image) + + if (type = "wicBitmap") + return ObjRelease(image) } } ; End of Destroy class. } ; End of ImagePut class. From 7ffaacc4242c66e53e55ae61db5492125f0b14d1 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 8 May 2022 23:36:55 -0400 Subject: [PATCH 245/492] 10x speed of set_hex 2.5x speed put_hex --- ImagePut (for v1).ahk | 46 +++++++++++++++++++++++++++++++++---------- ImagePut.ahk | 46 +++++++++++++++++++++++++++++++++---------- 2 files changed, 72 insertions(+), 20 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 80a187e3..06d6d66b 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2319,18 +2319,31 @@ class ImagePut { size := DllCall("GlobalSize", "ptr", bin, "uptr") ; Calculate the length of the hexadecimal string. - flags := 0x4000000C ; CRYPT_STRING_NOCRLF | CRYPT_STRING_HEXRAW - length := 2 * size + 1 ; An extra byte of padding is required. + length := 2 * size ; No zero terminator needed. VarSetCapacity(str, length) - ; Using CryptBinaryToStringA is faster and saves about 2MB in memory. - DllCall("crypt32\CryptBinaryToStringA", "ptr", bin, "uint", size, "uint", flags, "ptr", &str, "uint*", length) + ; C source code - https://godbolt.org/z/EqfK7fvr5 + static code := 0 + if !code { + code_str := (A_PtrSize == 4) + ? "VYnlVotFDIt1EFOLTRSLXQgBxjnwcyCKEIPBAkDA6gQPttKKFBOIUf6KUP+D4g+KFBOIUf/r3FteXcM=" + : "SQHQTDnCcyWKAkmDwQJI/8LA6AQPtsCKBAFBiEH+ikL/g+APigQBQYhB/+vWww==" + code_size := StrLen(RTrim(code_str, "=")) * 3 // 4 + code := DllCall("GlobalAlloc", "uint", 0, "uptr", code_size, "ptr") + DllCall("VirtualProtect", "ptr", code, "ptr", code_size, "uint", 0x40, "uint*", code_old:=0) + DllCall("crypt32\CryptStringToBinary", "str", code_str, "uint", 0, "uint", 0x1, "ptr", code, "uint*", code_size, "ptr", 0, "ptr", 0) + } + + ; Default to lowercase hex values. Or capitalize the string below. + VarSetCapacity(hex, 16) + StrPut("0123456789abcdef", &hex, "CP0") + DllCall(code, "ptr", &hex, "ptr", &bin, "uptr", size, "ptr", &str, "uptr", length) ; Release binary data and stream. DllCall("GlobalUnlock", "ptr", hbin) ObjRelease(pStream) - ; Return encoded string length minus 1. + ; Return encoded string from ANSI. return StrGet(&str, length, "CP0") } @@ -2342,14 +2355,27 @@ class ImagePut { DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") ; Calculate the length of the hexadecimal string. - flags := 0x4000000C ; CRYPT_STRING_NOCRLF | CRYPT_STRING_HEXRAW - length := 2 * size + 1 ; An extra byte of padding is required. + length := 2 * size ; No zero terminator needed. VarSetCapacity(str, length) - ; Using CryptBinaryToStringA is faster and saves about 2MB in memory. - DllCall("crypt32\CryptBinaryToStringA", "ptr", &bin, "uint", size, "uint", flags, "ptr", &str, "uint*", length) + ; C source code - https://godbolt.org/z/EqfK7fvr5 + static code := 0 + if !code { + code_str := (A_PtrSize == 4) + ? "VYnlVotFDIt1EFOLTRSLXQgBxjnwcyCKEIPBAkDA6gQPttKKFBOIUf6KUP+D4g+KFBOIUf/r3FteXcM=" + : "SQHQTDnCcyWKAkmDwQJI/8LA6AQPtsCKBAFBiEH+ikL/g+APigQBQYhB/+vWww==" + code_size := StrLen(RTrim(code_str, "=")) * 3 // 4 + code := DllCall("GlobalAlloc", "uint", 0, "uptr", code_size, "ptr") + DllCall("VirtualProtect", "ptr", code, "ptr", code_size, "uint", 0x40, "uint*", code_old:=0) + DllCall("crypt32\CryptStringToBinary", "str", code_str, "uint", 0, "uint", 0x1, "ptr", code, "uint*", code_size, "ptr", 0, "ptr", 0) + } - ; Return encoded string length minus 1. + ; Default to lowercase hex values. Or capitalize the string below. + VarSetCapacity(hex, 16) + StrPut("0123456789abcdef", &hex, "CP0") + DllCall(code, "ptr", &hex, "ptr", &bin, "uptr", size, "ptr", &str, "uptr", length) + + ; Return encoded string from ANSI. return StrGet(&str, length, "CP0") } diff --git a/ImagePut.ahk b/ImagePut.ahk index d9439603..e087371e 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2319,18 +2319,31 @@ class ImagePut { size := DllCall("GlobalSize", "ptr", bin, "uptr") ; Calculate the length of the hexadecimal string. - flags := 0x4000000C ; CRYPT_STRING_NOCRLF | CRYPT_STRING_HEXRAW - length := 2 * size + 1 ; An extra byte of padding is required. + length := 2 * size ; No zero terminator needed. str := Buffer(length) - ; Using CryptBinaryToStringA is faster and saves about 2MB in memory. - DllCall("crypt32\CryptBinaryToStringA", "ptr", bin, "uint", size, "uint", flags, "ptr", str, "uint*", &length) + ; C source code - https://godbolt.org/z/EqfK7fvr5 + static code := 0 + if !code { + code_str := (A_PtrSize == 4) + ? "VYnlVotFDIt1EFOLTRSLXQgBxjnwcyCKEIPBAkDA6gQPttKKFBOIUf6KUP+D4g+KFBOIUf/r3FteXcM=" + : "SQHQTDnCcyWKAkmDwQJI/8LA6AQPtsCKBAFBiEH+ikL/g+APigQBQYhB/+vWww==" + code_size := StrLen(RTrim(code_str, "=")) * 3 // 4 + code := DllCall("GlobalAlloc", "uint", 0, "uptr", code_size, "ptr") + DllCall("VirtualProtect", "ptr", code, "ptr", code_size, "uint", 0x40, "uint*", code_old:=0) + DllCall("crypt32\CryptStringToBinary", "str", code_str, "uint", 0, "uint", 0x1, "ptr", code, "uint*", code_size, "ptr", 0, "ptr", 0) + } + + ; Default to lowercase hex values. Or capitalize the string below. + hex := Buffer(16) + StrPut("0123456789abcdef", hex, "CP0") + DllCall(code, "ptr", hex, "ptr", bin, "uptr", size, "ptr", str, "uptr", length) ; Release binary data and stream. DllCall("GlobalUnlock", "ptr", hbin) ObjRelease(pStream) - ; Return encoded string length minus 1. + ; Return encoded string from ANSI. return StrGet(str, length, "CP0") } @@ -2342,14 +2355,27 @@ class ImagePut { DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") ; Calculate the length of the hexadecimal string. - flags := 0x4000000C ; CRYPT_STRING_NOCRLF | CRYPT_STRING_HEXRAW - length := 2 * size + 1 ; An extra byte of padding is required. + length := 2 * size ; No zero terminator needed. str := Buffer(length) - ; Using CryptBinaryToStringA is faster and saves about 2MB in memory. - DllCall("crypt32\CryptBinaryToStringA", "ptr", bin, "uint", size, "uint", flags, "ptr", str, "uint*", &length) + ; C source code - https://godbolt.org/z/EqfK7fvr5 + static code := 0 + if !code { + code_str := (A_PtrSize == 4) + ? "VYnlVotFDIt1EFOLTRSLXQgBxjnwcyCKEIPBAkDA6gQPttKKFBOIUf6KUP+D4g+KFBOIUf/r3FteXcM=" + : "SQHQTDnCcyWKAkmDwQJI/8LA6AQPtsCKBAFBiEH+ikL/g+APigQBQYhB/+vWww==" + code_size := StrLen(RTrim(code_str, "=")) * 3 // 4 + code := DllCall("GlobalAlloc", "uint", 0, "uptr", code_size, "ptr") + DllCall("VirtualProtect", "ptr", code, "ptr", code_size, "uint", 0x40, "uint*", code_old:=0) + DllCall("crypt32\CryptStringToBinary", "str", code_str, "uint", 0, "uint", 0x1, "ptr", code, "uint*", code_size, "ptr", 0, "ptr", 0) + } - ; Return encoded string length minus 1. + ; Default to lowercase hex values. Or capitalize the string below. + hex := Buffer(16) + StrPut("0123456789abcdef", hex, "CP0") + DllCall(code, "ptr", hex, "ptr", bin, "uptr", size, "ptr", str, "uptr", length) + + ; Return encoded string from ANSI. return StrGet(str, length, "CP0") } From 7682ea18519d651321bf43d7b00064523581d023 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 8 May 2022 23:39:06 -0400 Subject: [PATCH 246/492] C source files --- source/hex.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 source/hex.c diff --git a/source/hex.c b/source/hex.c new file mode 100644 index 00000000..8a1cc479 --- /dev/null +++ b/source/hex.c @@ -0,0 +1,17 @@ +#include + +void hex(char * hex, unsigned char * bin, size_t size, char * str, size_t length) { + unsigned char * start = bin; + unsigned char * end = bin + size; + char high, low; + char * s = str; + + while(start < end) { + high = (*start >> 4) & 0xF; + *s = *(hex + high); + low = *start & 0xF; + *(s + 1) = *(hex + low); + start += 1; + s += 2; + } +} \ No newline at end of file From 92cf1da9a3d6bae659cec8abf0f4debd627007f5 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 8 May 2022 23:57:45 -0400 Subject: [PATCH 247/492] Design Philosophy --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 50bf80c9..91b39a4c 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,12 @@ Finally, there are several advanced features. The first is the ability to specif ## Design Philosophy -ImagePut is designed to be fast. However, because of the nature of ImagePut, it has been designed to be as fast as possible for many to many, one to many, and many to one operations. If you find that your script relies on a single conversion of one input type to one output type, then you are advised to look at the source code and see what you need. Single conversions can be optimized in ImagePut by declaring an input type as shown above. If you copy and paste my source code, you may get an additional small gain. For certain operations on Windows that involve specific conversions from one specific file format & input type to another, such as a PNG file in memory to hIcon, there do exist even faster operations that I have not implemented because they are extremely specific and rely on little known behavior. +* ImagePut is designed to be fast. +* Only functions to and from streams, bitmaps are considered. +* Functions like PNG to hIcon are not considered. +* ImagePut should serve as a reference implementation. +* Therefore users should be able to copy and paste individual functions. +* If you need help extracting a function please ask! ## Help and Support From 8cd91441ddce9ed8edc9618677de691ef30b45df Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 11 May 2022 15:16:22 -0400 Subject: [PATCH 248/492] Buffer now supports cropping and showing windows --- ImagePut (for v1).ahk | 10 ++++++++++ ImagePut.ahk | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 06d6d66b..11e01c56 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1713,6 +1713,16 @@ class ImagePut { return Format("0x{:X}", NumGet(this.ptr + 4*(y*this.width + x), "uint")) } + Crop(x, y, w, h) { + DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", this.pBitmap, "int*", format:=0) + DllCall("gdiplus\GdipCloneBitmapAreaI", "int", x, "int", y, "int", w, "int", h, "int", format, "ptr", this.pBitmap, "ptr*", pBitmap:=0) + return new ImagePut.BitmapBuffer(pBitmap) + } + + Show(title := "", pos := "", style := 0x90000000, styleEx := 0x80088, parent := "") { + return ImagePut.show(this.pBitmap, title, pos, style, styleEx, parent) + } + Base64Put(code) { size := StrLen(RTrim(code, "=")) * 3 // 4 bin := DllCall("GlobalAlloc", "uint", 0, "uptr", size, "ptr") diff --git a/ImagePut.ahk b/ImagePut.ahk index e087371e..be6f683a 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1713,6 +1713,16 @@ class ImagePut { return Format("0x{:X}", NumGet(this.ptr + 4*(y*this.width + x), "uint")) } + Crop(x, y, w, h) { + DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", this.pBitmap, "int*", &format:=0) + DllCall("gdiplus\GdipCloneBitmapAreaI", "int", x, "int", y, "int", w, "int", h, "int", format, "ptr", this.pBitmap, "ptr*", &pBitmap:=0) + return ImagePut.BitmapBuffer(pBitmap) + } + + Show(title := "", pos := "", style := 0x90000000, styleEx := 0x80088, parent := "") { + return ImagePut.show(this.pBitmap, title, pos, style, styleEx, parent) + } + Base64Put(code) { size := StrLen(RTrim(code, "=")) * 3 // 4 bin := DllCall("GlobalAlloc", "uint", 0, "uptr", size, "ptr") From a1ada4e27834749e6b1a5ee147322316619d04a5 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 11 May 2022 16:36:45 -0400 Subject: [PATCH 249/492] Add setter to ImagePutBuffer --- ImagePut (for v1).ahk | 5 +++++ ImagePut.ahk | 9 +++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 11e01c56..f301ca6c 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1713,6 +1713,11 @@ class ImagePut { return Format("0x{:X}", NumGet(this.ptr + 4*(y*this.width + x), "uint")) } + __Set(x, y, color) { + NumPut(color, this.ptr + 4*(y*this.width + x), "uint") + return color + } + Crop(x, y, w, h) { DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", this.pBitmap, "int*", format:=0) DllCall("gdiplus\GdipCloneBitmapAreaI", "int", x, "int", y, "int", w, "int", h, "int", format, "ptr", this.pBitmap, "ptr*", pBitmap:=0) diff --git a/ImagePut.ahk b/ImagePut.ahk index be6f683a..a5beef44 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1709,10 +1709,15 @@ class ImagePut { DllCall("GlobalFree", "ptr", this.ptr) } - __Get(x, y) { - return Format("0x{:X}", NumGet(this.ptr + 4*(y*this.width + x), "uint")) + __Item[x, y] { + get => Format("0x{:X}", NumGet(this.ptr + 4*(y*this.width + x), "uint")) + set => (NumPut("uint", value, this.ptr + 4*(y*this.width + x)), value) } + + + + Crop(x, y, w, h) { DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", this.pBitmap, "int*", &format:=0) DllCall("gdiplus\GdipCloneBitmapAreaI", "int", x, "int", y, "int", w, "int", h, "int", format, "ptr", this.pBitmap, "ptr*", &pBitmap:=0) From 50d9cfec47fd6550177837862ca20a42a7901623 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 11 May 2022 16:42:40 -0400 Subject: [PATCH 250/492] Lift RGB colors to ARGB --- ImagePut (for v1).ahk | 1 + ImagePut.ahk | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index f301ca6c..6cb2bd8d 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1714,6 +1714,7 @@ class ImagePut { } __Set(x, y, color) { + (!(color >> 24)) && color |= 0xFF000000 NumPut(color, this.ptr + 4*(y*this.width + x), "uint") return color } diff --git a/ImagePut.ahk b/ImagePut.ahk index a5beef44..e572a7bf 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1711,13 +1711,14 @@ class ImagePut { __Item[x, y] { get => Format("0x{:X}", NumGet(this.ptr + 4*(y*this.width + x), "uint")) - set => (NumPut("uint", value, this.ptr + 4*(y*this.width + x)), value) + set => ((!(value >> 24)) && value |= 0xFF000000, + NumPut("uint", value, this.ptr + 4*(y*this.width + x)), + value) } - Crop(x, y, w, h) { DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", this.pBitmap, "int*", &format:=0) DllCall("gdiplus\GdipCloneBitmapAreaI", "int", x, "int", y, "int", w, "int", h, "int", format, "ptr", this.pBitmap, "ptr*", &pBitmap:=0) From 222ffff459562be4ba0dda824e1230137f62540e Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 11 May 2022 17:47:18 -0400 Subject: [PATCH 251/492] allow ImagePutBuffer().show to use window edges --- ImagePut (for v1).ahk | 6 ++++-- ImagePut.ahk | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 6cb2bd8d..6ddf52ce 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1725,8 +1725,10 @@ class ImagePut { return new ImagePut.BitmapBuffer(pBitmap) } - Show(title := "", pos := "", style := 0x90000000, styleEx := 0x80088, parent := "") { - return ImagePut.show(this.pBitmap, title, pos, style, styleEx, parent) + Show(window := False, title := "", pos := "", style := "", styleEx := "", parent := "") { + return (window) + ? ImagePut.put_window(this.pBitmap, title, pos, style, styleEx, parent) + : ImagePut.show(this.pBitmap, title, pos, style, styleEx, parent) } Base64Put(code) { diff --git a/ImagePut.ahk b/ImagePut.ahk index e572a7bf..817f98d7 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1725,8 +1725,10 @@ class ImagePut { return ImagePut.BitmapBuffer(pBitmap) } - Show(title := "", pos := "", style := 0x90000000, styleEx := 0x80088, parent := "") { - return ImagePut.show(this.pBitmap, title, pos, style, styleEx, parent) + Show(window := False, title := "", pos := "", style := "", styleEx := "", parent := "") { + return (window) + ? ImagePut.put_window(this.pBitmap, title, pos, style, styleEx, parent) + : ImagePut.show(this.pBitmap, title, pos, style, styleEx, parent) } Base64Put(code) { From c4de4433c79341f4483b986a035cafa635fd4a7d Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 11 May 2022 17:57:01 -0400 Subject: [PATCH 252/492] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 91b39a4c..b12ac44f 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,8 @@ * [Input Types & Output Functions](https://github.com/iseahound/ImagePut/wiki/Input-Types-&-Output-Functions) * [Crop, Scale, & Other Flags](https://github.com/iseahound/ImagePut/wiki/Crop,-Scale,-&-Other-Flags) +* [PixelSearch & ImageSearch](https://github.com/iseahound/ImagePut/wiki/PixelSearch-and-ImageSearch) * Chinese Documentation (中文) - [这里有一个中文版的使用教程](https://www.autoahk.com/archives/37246) -* [Internal Documentation](https://github.com/iseahound/ImagePut/wiki/Internal-Documentation) - Understanding how ImagePut works. * [Engineering Challenges Q&A](https://github.com/iseahound/ImagePut/wiki/Engineering-Challenges-Q&A) - Click here to read some interesting stuff. Projects using ImagePut: From 28f49f527237a80260b5e501d53939e360560568 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 12 May 2022 18:20:35 -0400 Subject: [PATCH 253/492] C source files --- source/cpuid.c | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/source/cpuid.c b/source/cpuid.c index ca11f3bd..5c48e0db 100644 --- a/source/cpuid.c +++ b/source/cpuid.c @@ -1,19 +1,9 @@ -void CPUID(unsigned long * a, unsigned long * b, unsigned long * c, unsigned long * d) -{ - __asm - { - mov eax, DWORD PTR [a] - mov eax, DWORD PTR [eax] - cpuid - push eax - mov eax, DWORD PTR [b] - mov DWORD PTR [eax], ebx - mov eax, DWORD PTR [c] - mov DWORD PTR [eax], ecx - mov eax, DWORD PTR [d] - mov DWORD PTR [eax], edx - pop eax - mov edx, DWORD PTR [a] - mov DWORD PTR [edx], eax - } +void native_cpuid(unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx) { + /* ecx is often an input as well as an output. */ + asm volatile("cpuid" + : "=a" (*eax), + "=b" (*ebx), + "=c" (*ecx), + "=d" (*edx) + : "0" (*eax), "2" (*ecx)); } \ No newline at end of file From 02501e879cde0faa52cc836ad4daf5eb5a1258d1 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 12 May 2022 18:21:28 -0400 Subject: [PATCH 254/492] C source files --- source/cpuid2.c | 38 -------------------------------------- 1 file changed, 38 deletions(-) delete mode 100644 source/cpuid2.c diff --git a/source/cpuid2.c b/source/cpuid2.c deleted file mode 100644 index 8edf713d..00000000 --- a/source/cpuid2.c +++ /dev/null @@ -1,38 +0,0 @@ -static inline void native_cpuid(unsigned int *eax, unsigned int *ebx, - unsigned int *ecx, unsigned int *edx) -{ - /* ecx is often an input as well as an output. */ - asm volatile("cpuid" - : "=a" (*eax), - "=b" (*ebx), - "=c" (*ecx), - "=d" (*edx) - : "0" (*eax), "2" (*ecx)); -} - -#include - -int main(int argc, char **argv) -{ - unsigned eax, ebx, ecx, edx; - - eax = 1; /* processor info and feature bits */ - native_cpuid(&eax, &ebx, &ecx, &edx); - - printf("stepping %d\n", eax & 0xF); - printf("model %d\n", (eax >> 4) & 0xF); - printf("family %d\n", (eax >> 8) & 0xF); - printf("processor type %d\n", (eax >> 12) & 0x3); - printf("extended model %d\n", (eax >> 16) & 0xF); - printf("extended family %d\n", (eax >> 20) & 0xFF); - - /* EDIT */ - eax = 3; /* processor serial number */ - native_cpuid(&eax, &ebx, &ecx, &edx); - - /** see the CPUID Wikipedia article on which models return the serial - number in which registers. The example here is for - Pentium III */ - printf("serial number 0x%08x%08x\n", edx, ecx); - -} \ No newline at end of file From f221ac1d0fcd3d455fb8b9d4e46ca8818534b1a5 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 12 May 2022 19:34:55 -0400 Subject: [PATCH 255/492] Add CPUID function --- ImagePut (for v1).ahk | 43 ++++++++++++++++++++++++++++++++----------- ImagePut.ahk | 43 ++++++++++++++++++++++++++++++++----------- 2 files changed, 64 insertions(+), 22 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 6ddf52ce..a007bfa6 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1740,18 +1740,39 @@ class ImagePut { } CPUID() { - ; C source code - https://godbolt.org/z/9v7vzf5az - static bin := 0, code := (A_PtrSize == 4) - ? "VYnlV4t9EFaLdQhTiw+LBg+iiQaLRQyJGItFFIkPiRBbXl9dww==" - : "U4sBSYnKSYnTQYsID6JBiQJBiRtBiQhBiRFbww==" - (!bin) && bin := this.Base64Put(code) + static cpuid := 0 + + if not cpuid { + ; C source code - https://godbolt.org/z/1YPd6jz61 + code := (A_PtrSize == 4) + ? "VYnlV4t9EFaLdQhTiw+LBg+iiQaLRQyJGItFFIkPiRBbXl9dww==" + : "U4sBSYnKSYnTQYsID6JBiQJBiRtBiQhBiRFbww==" + size := StrLen(RTrim(code, "=")) * 3 // 4 + bin := DllCall("GlobalAlloc", "uint", 0, "uptr", size, "ptr") + DllCall("VirtualProtect", "ptr", bin, "ptr", size, "uint", 0x40, "uint*", old:=0) + DllCall("crypt32\CryptStringToBinary", "str", code, "uint", 0, "uint", 0x1, "ptr", bin, "uint*", size, "ptr", 0, "ptr", 0) + + ; Set eax flag to 1 to retrieve supported CPU features. + ; See this for CPU features: https://wiki.osdev.org/CPUID + ; Also see page 591: https://www.amd.com/system/files/TechDocs/24594.pdf + DllCall(bin, "uint*", a := 1, "uint*", b := 0, "uint*", c := 0, "uint*", d := 0) + + ; To check for SSE2 use the following code example: + ; if image.cpuid().edx[26] == True + eax := {0: a & 1} + ebx := {0: b & 1} + ecx := {0: c & 1} + edx := {0: d & 1} + loop 32 { + eax[A_Index] := !!(1 << A_Index & a) + ebx[A_Index] := !!(1 << A_Index & b) + ecx[A_Index] := !!(1 << A_Index & c) + edx[A_Index] := !!(1 << A_Index & d) + } + cpuid := {eax: eax, ebx: ebx, ecx: ecx, edx: edx} + } - ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. - byte := DllCall(bin, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color:=0, "int") - if (byte == this.ptr + this.size) - return False - offset := (byte - this.ptr) // 4 - return [mod(offset, this.width), offset // this.width] + return cpuid } ColorKey(key := 0xFFFFFFFF, value := 0x00000000) { diff --git a/ImagePut.ahk b/ImagePut.ahk index 817f98d7..5946588f 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1740,18 +1740,39 @@ class ImagePut { } CPUID() { - ; C source code - https://godbolt.org/z/9v7vzf5az - static bin := 0, code := (A_PtrSize == 4) - ? "VYnlV4t9EFaLdQhTiw+LBg+iiQaLRQyJGItFFIkPiRBbXl9dww==" - : "U4sBSYnKSYnTQYsID6JBiQJBiRtBiQhBiRFbww==" - (!bin) && bin := this.Base64Put(code) + static cpuid := 0 + + if not cpuid { + ; C source code - https://godbolt.org/z/1YPd6jz61 + code := (A_PtrSize == 4) + ? "VYnlV4t9EFaLdQhTiw+LBg+iiQaLRQyJGItFFIkPiRBbXl9dww==" + : "U4sBSYnKSYnTQYsID6JBiQJBiRtBiQhBiRFbww==" + size := StrLen(RTrim(code, "=")) * 3 // 4 + bin := DllCall("GlobalAlloc", "uint", 0, "uptr", size, "ptr") + DllCall("VirtualProtect", "ptr", bin, "ptr", size, "uint", 0x40, "uint*", &old:=0) + DllCall("crypt32\CryptStringToBinary", "str", code, "uint", 0, "uint", 0x1, "ptr", bin, "uint*", size, "ptr", 0, "ptr", 0) + + ; Set eax flag to 1 to retrieve supported CPU features. + ; See this for CPU features: https://wiki.osdev.org/CPUID + ; Also see page 591: https://www.amd.com/system/files/TechDocs/24594.pdf + DllCall(bin, "uint*", &a := 1, "uint*", &b := 0, "uint*", &c := 0, "uint*", &d := 0) + + ; To check for SSE2 use the following code example: + ; if image.cpuid().edx[26] == True + eax := Map(0, a & 1) + ebx := Map(0, b & 1) + ecx := Map(0, c & 1) + edx := Map(0, d & 1) + loop 32 { + eax[A_Index] := !!(1 << A_Index & a) + ebx[A_Index] := !!(1 << A_Index & b) + ecx[A_Index] := !!(1 << A_Index & c) + edx[A_Index] := !!(1 << A_Index & d) + } + cpuid := {eax: eax, ebx: ebx, ecx: ecx, edx: edx} + } - ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. - byte := DllCall(bin, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color:=0, "int") - if (byte == this.ptr + this.size) - return False - offset := (byte - this.ptr) // 4 - return [mod(offset, this.width), offset // this.width] + return cpuid } ColorKey(key := 0xFFFFFFFF, value := 0x00000000) { From eef2a0f159fb2643cf989746939daa930ad965bd Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 12 May 2022 19:48:53 -0400 Subject: [PATCH 256/492] comment --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index a007bfa6..1cb2d22b 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1758,7 +1758,7 @@ class ImagePut { DllCall(bin, "uint*", a := 1, "uint*", b := 0, "uint*", c := 0, "uint*", d := 0) ; To check for SSE2 use the following code example: - ; if image.cpuid().edx[26] == True + ; if cpuid().edx[26] == True eax := {0: a & 1} ebx := {0: b & 1} ecx := {0: c & 1} diff --git a/ImagePut.ahk b/ImagePut.ahk index 5946588f..525562b2 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1758,7 +1758,7 @@ class ImagePut { DllCall(bin, "uint*", &a := 1, "uint*", &b := 0, "uint*", &c := 0, "uint*", &d := 0) ; To check for SSE2 use the following code example: - ; if image.cpuid().edx[26] == True + ; if cpuid().edx[26] == True eax := Map(0, a & 1) ebx := Map(0, b & 1) ecx := Map(0, c & 1) From b35505dc597d846c0977d427425e8acbede06845 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 12 May 2022 20:00:41 -0400 Subject: [PATCH 257/492] CPUID only uses 0-31 --- ImagePut (for v1).ahk | 5 ++++- ImagePut.ahk | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 1cb2d22b..4cc2b01a 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1757,13 +1757,16 @@ class ImagePut { ; Also see page 591: https://www.amd.com/system/files/TechDocs/24594.pdf DllCall(bin, "uint*", a := 1, "uint*", b := 0, "uint*", c := 0, "uint*", d := 0) + ; Free memory. + DllCall("GlobalFree", "ptr", bin) + ; To check for SSE2 use the following code example: ; if cpuid().edx[26] == True eax := {0: a & 1} ebx := {0: b & 1} ecx := {0: c & 1} edx := {0: d & 1} - loop 32 { + loop 31 { eax[A_Index] := !!(1 << A_Index & a) ebx[A_Index] := !!(1 << A_Index & b) ecx[A_Index] := !!(1 << A_Index & c) diff --git a/ImagePut.ahk b/ImagePut.ahk index 525562b2..dd39693d 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1757,13 +1757,16 @@ class ImagePut { ; Also see page 591: https://www.amd.com/system/files/TechDocs/24594.pdf DllCall(bin, "uint*", &a := 1, "uint*", &b := 0, "uint*", &c := 0, "uint*", &d := 0) + ; Free memory. + DllCall("GlobalFree", "ptr", bin) + ; To check for SSE2 use the following code example: ; if cpuid().edx[26] == True eax := Map(0, a & 1) ebx := Map(0, b & 1) ecx := Map(0, c & 1) edx := Map(0, d & 1) - loop 32 { + loop 31 { eax[A_Index] := !!(1 << A_Index & a) ebx[A_Index] := !!(1 << A_Index & b) ecx[A_Index] := !!(1 << A_Index & c) From 8c8d2ce3b36b0da9da9dbbedf273da8f614dab24 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 16 May 2022 21:05:07 -0400 Subject: [PATCH 258/492] Add pixelsearch with variation --- ImagePut (for v1).ahk | 50 +++++++++++++++++++++++++++++++++++++------ ImagePut.ahk | 50 +++++++++++++++++++++++++++++++++++++------ 2 files changed, 88 insertions(+), 12 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 4cc2b01a..26d0d48c 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1790,7 +1790,7 @@ class ImagePut { } SetAlpha(alpha := 0xFF) { - ; C source code - https://godbolt.org/z/6e1oYqxnW + ; C source code - https://godbolt.org/z/aWf73jTqc static bin := 0, code := (A_PtrSize == 4) ? "VYnli0UIilUQO0UMcwiIUAODwATr813D" : "SDnRcwpEiEEDSIPBBOvxww==" @@ -1801,7 +1801,7 @@ class ImagePut { } TransColor(color := 0xFFFFFF, alpha := 0x00) { - ; C source code - https://godbolt.org/z/6Wfd61qYE + ; C source code - https://godbolt.org/z/z3a8WcM5M static bin := 0, code := (A_PtrSize == 4) ? "VYnli0UIilUUO0UMcxWLTRAzCIHh////AHUDiFADg8AE6+Zdww==" : "SDnRcxaLAUQxwKn///8AdQREiEkDSIPBBOvlww==" @@ -1812,7 +1812,7 @@ class ImagePut { } PixelSearch(color) { - ; C source code - https://godbolt.org/z/9v7vzf5az + ; C source code - https://godbolt.org/z/o7EPo8xPr static bin := 0, code := (A_PtrSize == 4) ? "VYnli1UMi00Qi0UIOdBzCTkIdAeDwATr84nQXcM=" : "SInISDnQcwtEOQB0CUiDwATr8EiJ0MM=" @@ -1821,10 +1821,45 @@ class ImagePut { ; Lift color to 32-bits if first 8 bits are zero. (!(color >> 24)) && color |= 0xFF000000 + ; Get the address of the first matching pixel. + byte := DllCall(bin, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "ptr") + + ; Compare the address to the out-of-bounds limit. + if (byte == this.ptr + this.size) + return False + + ; Return an [x, y] array. + offset := (byte - this.ptr) // 4 + return [mod(offset, this.width), offset // this.width] + } + + PixelSearch2(color, variation := 3) { + ; C source code - https://godbolt.org/z/oocoPndE8 + static bin := 0, code := (A_PtrSize == 4) + ? "VYnlVlNRikUQilUcik0gil0ki3UIiEX3ikUUiEX2ikUYiEX1O3UMcyiKRgI6Rfd3GzpF9nIWikYBOkX1dw440HIKigY4yHcEONhzCIPGBOvTi3UMWonwW15dww==" + : "VlNEilQkOESKXCRAilwkSECKdCRQSInISDnQcyuKSAJEOMF3HUQ4yXIYikgBRDjRdxBEONlyC4oIONl3BUA48XMJSIPABOvQSInQW17D" + (!bin) && bin := this.Base64Put(code) + + v := variation + r := ((color & 0xFF0000) >> 16) + g := ((color & 0xFF00) >> 8) + b := ((color & 0xFF)) + ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. - byte := DllCall(bin, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "int") + byte := DllCall(bin, "ptr", this.ptr, "ptr", this.ptr + this.size + , "uchar", Min(r+v, 255) + , "uchar", Max(r-v, 0) + , "uchar", Min(g+v, 255) + , "uchar", Max(g-v, 0) + , "uchar", Min(b+v, 255) + , "uchar", Max(b-v, 0) + , "ptr") + + ; Compare the address to the out-of-bounds limit. if (byte == this.ptr + this.size) return False + + ; Return an [x, y] array. offset := (byte - this.ptr) // 4 return [mod(offset, this.width), offset // this.width] } @@ -1843,12 +1878,15 @@ class ImagePut { if ImagePut.ImageType(image) != "buffer" image := ImagePutBuffer(image) - ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. + ; Search for the address of the first matching image. byte := DllCall(bin, "ptr", this.ptr, "uint", this.width, "uint", this.height - , "ptr", image.ptr, "uint", image.width, "uint", image.height, "int") + , "ptr", image.ptr, "uint", image.width, "uint", image.height, "ptr") + ; Compare the address to the out-of-bounds limit. if (byte == this.ptr + this.size) return False + + ; Return an [x, y] array. offset := (byte - this.ptr) // 4 return [mod(offset, this.width), offset // this.width] } diff --git a/ImagePut.ahk b/ImagePut.ahk index dd39693d..87e64ec8 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1790,7 +1790,7 @@ class ImagePut { } SetAlpha(alpha := 0xFF) { - ; C source code - https://godbolt.org/z/6e1oYqxnW + ; C source code - https://godbolt.org/z/aWf73jTqc static bin := 0, code := (A_PtrSize == 4) ? "VYnli0UIilUQO0UMcwiIUAODwATr813D" : "SDnRcwpEiEEDSIPBBOvxww==" @@ -1801,7 +1801,7 @@ class ImagePut { } TransColor(color := 0xFFFFFF, alpha := 0x00) { - ; C source code - https://godbolt.org/z/6Wfd61qYE + ; C source code - https://godbolt.org/z/z3a8WcM5M static bin := 0, code := (A_PtrSize == 4) ? "VYnli0UIilUUO0UMcxWLTRAzCIHh////AHUDiFADg8AE6+Zdww==" : "SDnRcxaLAUQxwKn///8AdQREiEkDSIPBBOvlww==" @@ -1812,7 +1812,7 @@ class ImagePut { } PixelSearch(color) { - ; C source code - https://godbolt.org/z/9v7vzf5az + ; C source code - https://godbolt.org/z/o7EPo8xPr static bin := 0, code := (A_PtrSize == 4) ? "VYnli1UMi00Qi0UIOdBzCTkIdAeDwATr84nQXcM=" : "SInISDnQcwtEOQB0CUiDwATr8EiJ0MM=" @@ -1821,10 +1821,45 @@ class ImagePut { ; Lift color to 32-bits if first 8 bits are zero. (!(color >> 24)) && color |= 0xFF000000 + ; Get the address of the first matching pixel. + byte := DllCall(bin, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "ptr") + + ; Compare the address to the out-of-bounds limit. + if (byte == this.ptr + this.size) + return False + + ; Return an [x, y] array. + offset := (byte - this.ptr) // 4 + return [mod(offset, this.width), offset // this.width] + } + + PixelSearch2(color, variation := 3) { + ; C source code - https://godbolt.org/z/oocoPndE8 + static bin := 0, code := (A_PtrSize == 4) + ? "VYnlVlNRikUQilUcik0gil0ki3UIiEX3ikUUiEX2ikUYiEX1O3UMcyiKRgI6Rfd3GzpF9nIWikYBOkX1dw440HIKigY4yHcEONhzCIPGBOvTi3UMWonwW15dww==" + : "VlNEilQkOESKXCRAilwkSECKdCRQSInISDnQcyuKSAJEOMF3HUQ4yXIYikgBRDjRdxBEONlyC4oIONl3BUA48XMJSIPABOvQSInQW17D" + (!bin) && bin := this.Base64Put(code) + + v := variation + r := ((color & 0xFF0000) >> 16) + g := ((color & 0xFF00) >> 8) + b := ((color & 0xFF)) + ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. - byte := DllCall(bin, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "int") + byte := DllCall(bin, "ptr", this.ptr, "ptr", this.ptr + this.size + , "uchar", Min(r+v, 255) + , "uchar", Max(r-v, 0) + , "uchar", Min(g+v, 255) + , "uchar", Max(g-v, 0) + , "uchar", Min(b+v, 255) + , "uchar", Max(b-v, 0) + , "ptr") + + ; Compare the address to the out-of-bounds limit. if (byte == this.ptr + this.size) return False + + ; Return an [x, y] array. offset := (byte - this.ptr) // 4 return [mod(offset, this.width), offset // this.width] } @@ -1843,12 +1878,15 @@ class ImagePut { if ImagePut.ImageType(image) != "buffer" image := ImagePutBuffer(image) - ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. + ; Search for the address of the first matching image. byte := DllCall(bin, "ptr", this.ptr, "uint", this.width, "uint", this.height - , "ptr", image.ptr, "uint", image.width, "uint", image.height, "int") + , "ptr", image.ptr, "uint", image.width, "uint", image.height, "ptr") + ; Compare the address to the out-of-bounds limit. if (byte == this.ptr + this.size) return False + + ; Return an [x, y] array. offset := (byte - this.ptr) // 4 return [mod(offset, this.width), offset // this.width] } From 70df42bdcedb5ab5335adac1a425aa1f115db580 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 16 May 2022 21:05:25 -0400 Subject: [PATCH 259/492] C source files --- source/checkalpha.c | 8 ++++++++ source/pixelsearch.c | 9 ++++----- source/pixelsearch2.c | 12 ++++++++++++ source/setalpha.c | 2 +- source/transcolor.c | 2 +- 5 files changed, 26 insertions(+), 7 deletions(-) create mode 100644 source/checkalpha.c create mode 100644 source/pixelsearch2.c diff --git a/source/checkalpha.c b/source/checkalpha.c new file mode 100644 index 00000000..503c055b --- /dev/null +++ b/source/checkalpha.c @@ -0,0 +1,8 @@ +int checkalpha(unsigned int * start, unsigned int * end) { + while (start < end) { + if (*((char *) start + 3) > 0) + return 1; + start++; + } + return 0; +} \ No newline at end of file diff --git a/source/pixelsearch.c b/source/pixelsearch.c index fd35134d..72043d0b 100644 --- a/source/pixelsearch.c +++ b/source/pixelsearch.c @@ -1,9 +1,8 @@ unsigned int * pixelsearch(unsigned int * start, unsigned int * end, unsigned int color) { - unsigned int * current = start; - while (current < end) { - if (*current == color) - return current; - current++; + while (start < end) { + if (*start == color) + return start; + start++; } return end; } \ No newline at end of file diff --git a/source/pixelsearch2.c b/source/pixelsearch2.c new file mode 100644 index 00000000..cb2cdd4f --- /dev/null +++ b/source/pixelsearch2.c @@ -0,0 +1,12 @@ +unsigned int * pixelsearch2(unsigned int * start, unsigned int * end, unsigned char rh, unsigned char rl, unsigned char gh, unsigned char gl, unsigned char bh, unsigned char bl) { + unsigned char r, g, b; + while (start < end) { + r = *((unsigned char *) start + 2); + g = *((unsigned char *) start + 1); + b = *((unsigned char *) start + 0); + if (rh >= r && r >= rl && gh >= g && g >= gl && bh >= b && b >= bl) + return start; + start++; + } + return end; +} \ No newline at end of file diff --git a/source/setalpha.c b/source/setalpha.c index 69ac4c33..55d72ae9 100644 --- a/source/setalpha.c +++ b/source/setalpha.c @@ -1,6 +1,6 @@ void setalpha(unsigned int * start, unsigned int * end, unsigned char alpha) { while (start < end) { - *((char *) start + 3) = alpha; + *((unsigned char *) start + 3) = alpha; start++; } } \ No newline at end of file diff --git a/source/transcolor.c b/source/transcolor.c index d7fae951..2d0428f3 100644 --- a/source/transcolor.c +++ b/source/transcolor.c @@ -1,7 +1,7 @@ void transcolor(unsigned int * start, unsigned int * end, unsigned int color, unsigned char alpha) { while (start < end) { if ((*start & 0xFFFFFF) == (color & 0xFFFFFF)) - *((char *) start + 3) = alpha; + *((unsigned char *) start + 3) = alpha; start++; } } \ No newline at end of file From ef0838bdb1da93ac2b055a38436d1e3f27ae636e Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 18 May 2022 12:04:42 -0400 Subject: [PATCH 260/492] Fix colon : being removed from Drive path --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 26d0d48c..5435ea7b 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2745,7 +2745,7 @@ class ImagePut { ; Split the filepath, convert forward slashes, strip invalid chars. filepath := RegExReplace(filepath, "/", "\") - filepath := RegExReplace(filepath, "[:*?\x22<>|\x00-\x1F]") + filepath := RegExReplace(filepath, "[*?\x22<>|\x00-\x1F]") SplitPath % filepath,, directory, extension, filename ; Check if the entire filepath is a directory. diff --git a/ImagePut.ahk b/ImagePut.ahk index 87e64ec8..05dffdec 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2745,7 +2745,7 @@ class ImagePut { ; Split the filepath, convert forward slashes, strip invalid chars. filepath := RegExReplace(filepath, "/", "\") - filepath := RegExReplace(filepath, "[:*?\x22<>|\x00-\x1F]") + filepath := RegExReplace(filepath, "[*?\x22<>|\x00-\x1F]") SplitPath filepath,, &directory, &extension, &filename ; Check if the entire filepath is a directory. From f1f0a25c1b130b7a21588e4a457d0c79fbc45b8a Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 22 May 2022 02:26:34 -0400 Subject: [PATCH 261/492] Use the && short-circuit to simplify ternaries --- ImagePut (for v1).ahk | 48 +++++++++++++++++++++---------------------- ImagePut.ahk | 48 +++++++++++++++++++++---------------------- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 5435ea7b..883765b4 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -202,9 +202,9 @@ class ImagePut { ; Convert via GDI+ bitmap intermediate. if !(pBitmap := this.ToBitmap(type, image, keywords)) throw Exception("pBitmap cannot be zero.") - (validate) ? DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmap) : {} - (crop) ? this.BitmapCrop(pBitmap, crop) : {} - (scale) ? this.BitmapScale(pBitmap, scale) : {} + (validate) && DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmap) + (crop) && this.BitmapCrop(pBitmap, crop) + (scale) && this.BitmapScale(pBitmap, scale) coimage := this.BitmapToCoimage(cotype, pBitmap, p*) ; Clean up the pBitmap copy. Export raw pointers if requested. @@ -639,10 +639,10 @@ class ImagePut { ; Now, real values have been resolved, and abstract values depend on reals. ; Are the numbers percentages? - crop[1] := (crop[1] ~= "%$") ? SubStr(crop[1], 1, -1) * 0.01 * width : crop[1] - crop[2] := (crop[2] ~= "%$") ? SubStr(crop[2], 1, -1) * 0.01 * height : crop[2] - crop[3] := (crop[3] ~= "%$") ? SubStr(crop[3], 1, -1) * 0.01 * width : crop[3] - crop[4] := (crop[4] ~= "%$") ? SubStr(crop[4], 1, -1) * 0.01 * height : crop[4] + (crop[1] ~= "%$") && crop[1] := SubStr(crop[1], 1, -1) * 0.01 * width + (crop[2] ~= "%$") && crop[2] := SubStr(crop[2], 1, -1) * 0.01 * height + (crop[3] ~= "%$") && crop[3] := SubStr(crop[3], 1, -1) * 0.01 * width + (crop[4] ~= "%$") && crop[4] := SubStr(crop[4], 1, -1) * 0.01 * height ; If numbers are negative, subtract the values from the edge. crop[1] := Abs(crop[1]) @@ -1033,7 +1033,7 @@ class ImagePut { get_pdf(image, index := "") { ; Thanks malcev - https://www.autohotkey.com/boards/viewtopic.php?t=80735 - index := (index != "") ? index : 1 + (index == "") && index := 1 ; Create a stream from either a url or a file. pStream := this.is_url(image) ? this.get_url(image) : this.get_file(image) @@ -1725,8 +1725,8 @@ class ImagePut { return new ImagePut.BitmapBuffer(pBitmap) } - Show(window := False, title := "", pos := "", style := "", styleEx := "", parent := "") { - return (window) + Show(window_border := False, title := "", pos := "", style := "", styleEx := "", parent := "") { + return (window_border) ? ImagePut.put_window(this.pBitmap, title, pos, style, styleEx, parent) : ImagePut.show(this.pBitmap, title, pos, style, styleEx, parent) } @@ -1947,9 +1947,9 @@ class ImagePut { WS_VISIBLE := 0x10000000 ; Show on creation. WS_EX_LAYERED := 0x80000 ; For UpdateLayeredWindow. - ; Set default styles if null. - style := (style == "") ? WS_POPUP | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU : style - styleEx := (styleEx == "") ? WS_EX_TOPMOST | WS_EX_DLGMODALFRAME : styleEx + ; Default styles can be overwritten by previous functions. + (style == "") && style := WS_POPUP | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU + (styleEx == "") && styleEx := WS_EX_TOPMOST | WS_EX_DLGMODALFRAME ; Get Bitmap width and height. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) @@ -2029,9 +2029,9 @@ class ImagePut { WS_EX_TOOLWINDOW := 0x80 ; Hides from Alt+Tab menu. Removes small icon. WS_EX_LAYERED := 0x80000 ; For UpdateLayeredWindow. - ; Set default styles if null. - style := (style == "") ? WS_POPUP | WS_VISIBLE : style - styleEx := (styleEx == "") ? WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_EX_LAYERED : styleEx + ; Default styles can be overwritten by previous functions. + (style == "") && style := WS_POPUP | WS_VISIBLE + (styleEx == "") && styleEx := WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_EX_LAYERED ; Prevent the script from exiting early. void := ObjBindMethod({}, {}) @@ -2315,13 +2315,13 @@ class ImagePut { ; Sets the hotspot of the cursor by changing the icon into a cursor. if (xHotspot ~= "^\d+$" || yHotspot ~= "^\d+$") { ; struct ICONINFO - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-iconinfo - VarSetCapacity(ii, 8+3*A_PtrSize) ; sizeof(ICONINFO) = 20, 32 - DllCall("GetIconInfo", "ptr", hIcon, "ptr", &ii) ; Fill the ICONINFO structure. - NumPut(False, ii, 0, "uint") ; True/False are icon/cursor respectively. - (xHotspot ~= "^\d+$") ? NumPut(xHotspot, ii, 4, "uint") : {} ; Set the xHotspot value. Default: center point - (yHotspot ~= "^\d+$") ? NumPut(yHotspot, ii, 8, "uint") : {} ; Set the yHotspot value. Default: center point - DllCall("DestroyIcon", "ptr", hIcon) ; Destroy the icon after getting the ICONINFO structure. - hIcon := DllCall("CreateIconIndirect", "ptr", &ii, "ptr") ; Create a new cursor using ICONINFO. + VarSetCapacity(ii, 8+3*A_PtrSize) ; sizeof(ICONINFO) = 20, 32 + DllCall("GetIconInfo", "ptr", hIcon, "ptr", &ii) ; Fill the ICONINFO structure. + NumPut(False, ii, 0, "uint") ; True/False are icon/cursor respectively. + (xHotspot ~= "^\d+$") && NumPut(xHotspot, ii, 4, "uint") ; Set the xHotspot value. Default: center point + (yHotspot ~= "^\d+$") && NumPut(yHotspot, ii, 8, "uint") ; Set the yHotspot value. Default: center point + DllCall("DestroyIcon", "ptr", hIcon) ; Destroy the icon after getting the ICONINFO structure. + hIcon := DllCall("CreateIconIndirect", "ptr", &ii, "ptr") ; Create a new cursor using ICONINFO. ; Clean up hbmMask and hbmColor created as a result of GetIconInfo. DllCall("DeleteObject", "ptr", NumGet(ii, 8+A_PtrSize, "ptr")) ; hbmMask @@ -2764,7 +2764,7 @@ class ImagePut { FileCreateDir % directory ; Default directory is a dot. - directory := (directory != "") ? directory : "." + (directory == "") && directory := "." ; Check if the filename is actually the extension. if (extension == "" && filename ~= "^(?i:bmp|dib|rle|jpg|jpeg|jpe|jfif|gif|tif|tiff|png)$") diff --git a/ImagePut.ahk b/ImagePut.ahk index 05dffdec..6dccd478 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -202,9 +202,9 @@ class ImagePut { ; Convert via GDI+ bitmap intermediate. if !(pBitmap := this.ToBitmap(type, image, keywords)) throw Error("pBitmap cannot be zero.") - (validate) ? DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmap) : {} - (crop) ? this.BitmapCrop(&pBitmap, crop) : {} - (scale) ? this.BitmapScale(&pBitmap, scale) : {} + (validate) && DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmap) + (crop) && this.BitmapCrop(&pBitmap, crop) + (scale) && this.BitmapScale(&pBitmap, scale) coimage := this.BitmapToCoimage(cotype, pBitmap, p*) ; Clean up the pBitmap copy. Export raw pointers if requested. @@ -639,10 +639,10 @@ class ImagePut { ; Now, real values have been resolved, and abstract values depend on reals. ; Are the numbers percentages? - crop[1] := (crop[1] ~= "%$") ? SubStr(crop[1], 1, -1) * 0.01 * width : crop[1] - crop[2] := (crop[2] ~= "%$") ? SubStr(crop[2], 1, -1) * 0.01 * height : crop[2] - crop[3] := (crop[3] ~= "%$") ? SubStr(crop[3], 1, -1) * 0.01 * width : crop[3] - crop[4] := (crop[4] ~= "%$") ? SubStr(crop[4], 1, -1) * 0.01 * height : crop[4] + (crop[1] ~= "%$") && crop[1] := SubStr(crop[1], 1, -1) * 0.01 * width + (crop[2] ~= "%$") && crop[2] := SubStr(crop[2], 1, -1) * 0.01 * height + (crop[3] ~= "%$") && crop[3] := SubStr(crop[3], 1, -1) * 0.01 * width + (crop[4] ~= "%$") && crop[4] := SubStr(crop[4], 1, -1) * 0.01 * height ; If numbers are negative, subtract the values from the edge. crop[1] := Abs(crop[1]) @@ -1033,7 +1033,7 @@ class ImagePut { static get_pdf(image, index := "") { ; Thanks malcev - https://www.autohotkey.com/boards/viewtopic.php?t=80735 - index := (index != "") ? index : 1 + (index == "") && index := 1 ; Create a stream from either a url or a file. pStream := this.is_url(image) ? this.get_url(image) : this.get_file(image) @@ -1725,8 +1725,8 @@ class ImagePut { return ImagePut.BitmapBuffer(pBitmap) } - Show(window := False, title := "", pos := "", style := "", styleEx := "", parent := "") { - return (window) + Show(window_border := False, title := "", pos := "", style := "", styleEx := "", parent := "") { + return (window_border) ? ImagePut.put_window(this.pBitmap, title, pos, style, styleEx, parent) : ImagePut.show(this.pBitmap, title, pos, style, styleEx, parent) } @@ -1947,9 +1947,9 @@ class ImagePut { WS_VISIBLE := 0x10000000 ; Show on creation. WS_EX_LAYERED := 0x80000 ; For UpdateLayeredWindow. - ; Set default styles if null. - style := (style == "") ? WS_POPUP | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU : style - styleEx := (styleEx == "") ? WS_EX_TOPMOST | WS_EX_DLGMODALFRAME : styleEx + ; Default styles can be overwritten by previous functions. + (style == "") && style := WS_POPUP | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU + (styleEx == "") && styleEx := WS_EX_TOPMOST | WS_EX_DLGMODALFRAME ; Get Bitmap width and height. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) @@ -2029,9 +2029,9 @@ class ImagePut { WS_EX_TOOLWINDOW := 0x80 ; Hides from Alt+Tab menu. Removes small icon. WS_EX_LAYERED := 0x80000 ; For UpdateLayeredWindow. - ; Set default styles if null. - style := (style == "") ? WS_POPUP | WS_VISIBLE : style - styleEx := (styleEx == "") ? WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_EX_LAYERED : styleEx + ; Default styles can be overwritten by previous functions. + (style == "") && style := WS_POPUP | WS_VISIBLE + (styleEx == "") && styleEx := WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_EX_LAYERED ; Prevent the script from exiting early. Persistent(True) @@ -2315,13 +2315,13 @@ class ImagePut { ; Sets the hotspot of the cursor by changing the icon into a cursor. if (xHotspot ~= "^\d+$" || yHotspot ~= "^\d+$") { ; struct ICONINFO - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-iconinfo - ii := Buffer(8+3*A_PtrSize) ; sizeof(ICONINFO) = 20, 32 - DllCall("GetIconInfo", "ptr", hIcon, "ptr", ii) ; Fill the ICONINFO structure. - NumPut("uint", False, ii, 0) ; True/False are icon/cursor respectively. - (xHotspot ~= "^\d+$") ? NumPut("uint", xHotspot, ii, 4) : {} ; Set the xHotspot value. Default: center point - (yHotspot ~= "^\d+$") ? NumPut("uint", yHotspot, ii, 8) : {} ; Set the yHotspot value. Default: center point - DllCall("DestroyIcon", "ptr", hIcon) ; Destroy the icon after getting the ICONINFO structure. - hIcon := DllCall("CreateIconIndirect", "ptr", ii, "ptr") ; Create a new cursor using ICONINFO. + ii := Buffer(8+3*A_PtrSize) ; sizeof(ICONINFO) = 20, 32 + DllCall("GetIconInfo", "ptr", hIcon, "ptr", ii) ; Fill the ICONINFO structure. + NumPut("uint", False, ii, 0) ; True/False are icon/cursor respectively. + (xHotspot ~= "^\d+$") && NumPut("uint", xHotspot, ii, 4) ; Set the xHotspot value. Default: center point + (yHotspot ~= "^\d+$") && NumPut("uint", yHotspot, ii, 8) ; Set the yHotspot value. Default: center point + DllCall("DestroyIcon", "ptr", hIcon) ; Destroy the icon after getting the ICONINFO structure. + hIcon := DllCall("CreateIconIndirect", "ptr", ii, "ptr") ; Create a new cursor using ICONINFO. ; Clean up hbmMask and hbmColor created as a result of GetIconInfo. DllCall("DeleteObject", "ptr", NumGet(ii, 8+A_PtrSize, "ptr")) ; hbmMask @@ -2764,7 +2764,7 @@ class ImagePut { DirCreate(directory) ; Default directory is a dot. - directory := (directory != "") ? directory : "." + (directory == "") && directory := "." ; Check if the filename is actually the extension. if (extension == "" && filename ~= "^(?i:bmp|dib|rle|jpg|jpeg|jpe|jfif|gif|tif|tiff|png)$") From 1998b3d3cd55d8713fe3a02e9513ed9eac586f20 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 22 May 2022 02:32:32 -0400 Subject: [PATCH 262/492] MimeType typo --- ImagePut (for v1).ahk | 4 ++-- ImagePut.ahk | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 883765b4..8c1ac645 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2534,7 +2534,7 @@ class ImagePut { , "ptr*", MimeOut:=0 ; ppwzMimeOut , "uint", 0 ; dwReserved , "uint") - MimeType := StrGet(MimeType, "UTF-16") + MimeType := StrGet(MimeOut, "UTF-16") DllCall("ole32\CoTaskMemFree", "ptr", MimeOut) return "data:" MimeType ";base64," this.set_base64(pStream) @@ -2724,7 +2724,7 @@ class ImagePut { , "ptr*", MimeOut:=0 ; ppwzMimeOut , "uint", 0 ; dwReserved , "uint") - MimeType := StrGet(MimeType, "UTF-16") + MimeType := StrGet(MimeOut, "UTF-16") DllCall("ole32\CoTaskMemFree", "ptr", MimeOut) if (MimeType ~= "gif") diff --git a/ImagePut.ahk b/ImagePut.ahk index 6dccd478..63251d1a 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2534,7 +2534,7 @@ class ImagePut { , "ptr*", &MimeOut:=0 ; ppwzMimeOut , "uint", 0 ; dwReserved ,"HRESULT") - MimeType := StrGet(MimeType, "UTF-16") + MimeType := StrGet(MimeOut, "UTF-16") DllCall("ole32\CoTaskMemFree", "ptr", MimeOut) return "data:" MimeType ";base64," this.set_base64(pStream) @@ -2724,7 +2724,7 @@ class ImagePut { , "ptr*", &MimeOut:=0 ; ppwzMimeOut , "uint", 0 ; dwReserved ,"HRESULT") - MimeType := StrGet(MimeType, "UTF-16") + MimeType := StrGet(MimeOut, "UTF-16") DllCall("ole32\CoTaskMemFree", "ptr", MimeOut) if (MimeType ~= "gif") From 7650cb1ef794b0dbdeb0c39efb70ad4fd6e34b04 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 23 May 2022 15:46:24 -0400 Subject: [PATCH 263/492] Fix put_hex incorrect pointer to GlobalLock --- ImagePut (for v1).ahk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 8c1ac645..7ca2f7f2 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2417,7 +2417,7 @@ class ImagePut { ; Default to lowercase hex values. Or capitalize the string below. VarSetCapacity(hex, 16) StrPut("0123456789abcdef", &hex, "CP0") - DllCall(code, "ptr", &hex, "ptr", &bin, "uptr", size, "ptr", &str, "uptr", length) + DllCall(code, "ptr", &hex, "ptr", bin, "uptr", size, "ptr", &str, "uptr", length) ; Release binary data and stream. DllCall("GlobalUnlock", "ptr", hbin) From 9d732c2015aee2767ff82cdd7fe20d8c3a91a54c Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 23 May 2022 15:57:21 -0400 Subject: [PATCH 264/492] Remove "smart_pointer" type from GdiplusShutdown --- ImagePut (for v1).ahk | 8 ++------ ImagePut.ahk | 8 ++------ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 7ca2f7f2..0c5a42ce 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1705,8 +1705,9 @@ class ImagePut { } __Delete() { - ImagePut.gdiplusShutdown("smart_pointer", this.pBitmap) + DllCall("gdiplus\GdipDisposeImage", "ptr", this.pBitmap) DllCall("GlobalFree", "ptr", this.ptr) + ImagePut.gdiplusShutdown() } __Get(x, y) { @@ -2821,11 +2822,6 @@ class ImagePut { gdiplusShutdown(cotype := "", pBitmap := "") { ImagePut.gdiplus-- - ; When a buffer object is deleted a bitmap is sent here for disposal. - if (cotype == "smart_pointer") - if DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) - throw Exception("The bitmap of this buffer object has already been deleted.") - ; Check for unpaired calls of gdiplusShutdown. if (ImagePut.gdiplus < 0) throw Exception("Missing ImagePut.gdiplusStartup().") diff --git a/ImagePut.ahk b/ImagePut.ahk index 63251d1a..fd1570fe 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1705,8 +1705,9 @@ class ImagePut { } __Delete() { - ImagePut.gdiplusShutdown("smart_pointer", this.pBitmap) + DllCall("gdiplus\GdipDisposeImage", "ptr", this.pBitmap) DllCall("GlobalFree", "ptr", this.ptr) + ImagePut.gdiplusShutdown() } __Item[x, y] { @@ -2821,11 +2822,6 @@ class ImagePut { static gdiplusShutdown(cotype := "", pBitmap := "") { ImagePut.gdiplus-- - ; When a buffer object is deleted a bitmap is sent here for disposal. - if (cotype == "smart_pointer") - if DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) - throw Error("The bitmap of this buffer object has already been deleted.") - ; Check for unpaired calls of gdiplusShutdown. if (ImagePut.gdiplus < 0) throw Error("Missing ImagePut.gdiplusStartup().") From df74fcba1dd30b7aa37b783c829a4b33621e0ec6 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 23 May 2022 15:59:20 -0400 Subject: [PATCH 265/492] Change obj.pBitmap to pic.pBitmap --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 0c5a42ce..ea2974e7 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2844,7 +2844,7 @@ class ImagePut { if (cotype = "bitmap") throw Exception("Bitmap is out of scope. `n`nIf you wish to handle raw pointers to GDI+ bitmaps, add the line" . "`n`n`t`t" this.__class ".gdiplusStartup()`n`nor 'pToken := Gdip_Startup()' to the top of your script." - . "`nAlternatively, use 'obj := ImagePutBuffer()' with 'obj.pBitmap'." + . "`nAlternatively, use 'pic := ImagePutBuffer()' with 'pic.pBitmap'." . "`nYou can copy this message by pressing Ctrl + C.", -4) } } diff --git a/ImagePut.ahk b/ImagePut.ahk index fd1570fe..34b98cfa 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2844,7 +2844,7 @@ class ImagePut { if (cotype = "bitmap") throw Error("Bitmap is out of scope. `n`nIf you wish to handle raw pointers to GDI+ bitmaps, add the line" . "`n`n`t`t" this.prototype.__class ".gdiplusStartup()`n`nor 'pToken := Gdip_Startup()' to the top of your script." - . "`nAlternatively, use 'obj := ImagePutBuffer()' with 'obj.pBitmap'." + . "`nAlternatively, use 'pic := ImagePutBuffer()' with 'pic.pBitmap'." . "`nYou can copy this message by pressing Ctrl + C.", -3) } } From d1d9225055ab8cd41e97bee019ab7d1e03fdaaac Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 23 May 2022 16:14:19 -0400 Subject: [PATCH 266/492] Remove unused parameter in GdiplusShutdown --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index ea2974e7..4623a83f 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2819,7 +2819,7 @@ class ImagePut { } } - gdiplusShutdown(cotype := "", pBitmap := "") { + gdiplusShutdown(cotype := "") { ImagePut.gdiplus-- ; Check for unpaired calls of gdiplusShutdown. diff --git a/ImagePut.ahk b/ImagePut.ahk index 34b98cfa..6d4fd51f 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2819,7 +2819,7 @@ class ImagePut { } } - static gdiplusShutdown(cotype := "", pBitmap := "") { + static gdiplusShutdown(cotype := "") { ImagePut.gdiplus-- ; Check for unpaired calls of gdiplusShutdown. From 8537c07c40d4dc53c62f52c6e48ea19243e5abfa Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 24 May 2022 13:46:59 -0400 Subject: [PATCH 267/492] remove annoying comments from select_ --- ImagePut (for v1).ahk | 6 +----- ImagePut.ahk | 3 --- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 4623a83f..009ba176 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1544,8 +1544,7 @@ class ImagePut { ? "VYnli0UIi1UMi00QjRSQOdBzDzkIdQbHAAAAAACDwATr7V3D" : "idJIjQSRSDnBcxFEOQF1BscBAAAAAEiDwQTr6sM=" size := StrLen(RTrim(code, "=")) * 3 // 4 - bin := DllCall("GlobalAlloc", "uint", 0, "uptr", size, "ptr") - DllCall("VirtualProtect", "ptr", bin, "ptr", size, "uint", 0x40, "uint*", old:=0) + bin := DllCall("VirtualAlloc", "ptr", 0, "uptr", size, "uint", 0x00003000, "uint", 0x40) DllCall("crypt32\CryptStringToBinary", "str", code, "uint", 0, "uint", 0x1, "ptr", bin, "uint*", size, "ptr", 0, "ptr", 0) } @@ -2346,8 +2345,6 @@ class ImagePut { ; Thanks tic - https://www.autohotkey.com/boards/viewtopic.php?t=6517 extension := "png" this.select_filepath(filepath, extension) - - ; Select the proper codec based on the extension of the file. this.select_codec(pBitmap, extension, quality, pCodec, ep, ci, v) ; Write the file to disk using the specified encoder and encoding parameters with exponential backoff. @@ -2605,7 +2602,6 @@ class ImagePut { if (extension == "") extension := "tif" - ; Select the proper codec based on the extension of the file. this.select_codec(pBitmap, extension, quality, pCodec, ep, ci, v) ; Create a Stream. diff --git a/ImagePut.ahk b/ImagePut.ahk index 6d4fd51f..6616b597 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2346,8 +2346,6 @@ class ImagePut { ; Thanks tic - https://www.autohotkey.com/boards/viewtopic.php?t=6517 extension := "png" this.select_filepath(&filepath, &extension) - - ; Select the proper codec based on the extension of the file. this.select_codec(pBitmap, extension, quality, &pCodec, &ep, &ci, &v) ; Write the file to disk using the specified encoder and encoding parameters with exponential backoff. @@ -2605,7 +2603,6 @@ class ImagePut { if (extension == "") extension := "tif" - ; Select the proper codec based on the extension of the file. this.select_codec(pBitmap, extension, quality, &pCodec, &ep, &ci, &v) ; Create a Stream. From e39f1019137285088b34c20f8e059b3abc5a978e Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 28 May 2022 14:59:29 -0400 Subject: [PATCH 268/492] WindowProc new thread should be critical --- ImagePut (for v1).ahk | 1 + ImagePut.ahk | 1 + 2 files changed, 2 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 009ba176..72863682 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2203,6 +2203,7 @@ class ImagePut { } ; Define window behavior. WindowProc(uMsg, wParam, lParam) { + Critical ; Thread must never be interrupted. hwnd := this ; WM_DESTROY if (uMsg = 0x2) { diff --git a/ImagePut.ahk b/ImagePut.ahk index 6616b597..b37861a0 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2204,6 +2204,7 @@ class ImagePut { ; Define window behavior. WindowProc(hwnd, uMsg, wParam, lParam) { + Critical ; Thread must never be interrupted. ; WM_DESTROY if (uMsg = 0x2) { From 3fb80f4e31a066a05f172036be3af3750474e6c7 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 1 Jun 2022 14:12:36 -0400 Subject: [PATCH 269/492] Fix gdiplus remaining loaded with streams --- ImagePut (for v1).ahk | 2 -- ImagePut.ahk | 2 -- 2 files changed, 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 72863682..efb47b07 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -189,8 +189,6 @@ class ImagePut { ; Free the temporary stream object. ObjRelease(pStream) - - return coimage } ; #2 - Fallback to GDI+ bitmap as the intermediate. diff --git a/ImagePut.ahk b/ImagePut.ahk index b37861a0..a6a014ef 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -189,8 +189,6 @@ class ImagePut { ; Free the temporary stream object. ObjRelease(pStream) - - return coimage } ; #2 - Fallback to GDI+ bitmap as the intermediate. From 5cdf2d8ba587cbf2ad6b4f9ddc644ca80e3056fd Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 1 Jun 2022 14:27:29 -0400 Subject: [PATCH 270/492] Try-Finally to avoid intermediate values --- ImagePut (for v1).ahk | 3 ++- ImagePut.ahk | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index efb47b07..15f7f5cc 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2874,7 +2874,8 @@ class ImagePut { if (type = "clipboard") { if !DllCall("OpenClipboard", "ptr", A_ScriptHwnd) throw Exception("Clipboard could not be opened.") - return DllCall("EmptyClipboard"), DllCall("CloseClipboard") + try return DllCall("EmptyClipboard") + finally DllCall("CloseClipboard") } if (type = "screenshot") diff --git a/ImagePut.ahk b/ImagePut.ahk index a6a014ef..b75c07de 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2875,7 +2875,8 @@ class ImagePut { if (type = "clipboard") { if !DllCall("OpenClipboard", "ptr", A_ScriptHwnd) throw Error("Clipboard could not be opened.") - return ((_,*)=>_)(DllCall("EmptyClipboard"), DllCall("CloseClipboard")) + try return DllCall("EmptyClipboard") + finally DllCall("CloseClipboard") } if (type = "screenshot") From 255fa3bfdc64c2188a295974bf46765b106fb5eb Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 1 Jun 2022 14:40:05 -0400 Subject: [PATCH 271/492] some comments --- ImagePut (for v1).ahk | 6 ++---- ImagePut.ahk | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 15f7f5cc..d9f9cac2 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2801,10 +2801,9 @@ class ImagePut { gdiplusStartup() { ImagePut.gdiplus++ - ; Startup gdiplus when counter goes from 0 -> 1. + ; Startup gdiplus when counter rises from 0 -> 1. if (ImagePut.gdiplus == 1) { - ; Startup gdiplus. DllCall("LoadLibrary", "str", "gdiplus") VarSetCapacity(si, A_PtrSize = 4 ? 16:24, 0) ; sizeof(GdiplusStartupInput) = 16, 24 NumPut(0x1, si, "uint") @@ -2821,11 +2820,10 @@ class ImagePut { if (ImagePut.gdiplus < 0) throw Exception("Missing ImagePut.gdiplusStartup().") - ; Shutdown gdiplus when counter goes from 1 -> 0. + ; Shutdown gdiplus when counter falls from 1 -> 0. if (ImagePut.gdiplus == 0) { pToken := ImagePut.pToken - ; Shutdown gdiplus. DllCall("gdiplus\GdiplusShutdown", "ptr", pToken) DllCall("FreeLibrary", "ptr", DllCall("GetModuleHandle", "str", "gdiplus", "ptr")) diff --git a/ImagePut.ahk b/ImagePut.ahk index b75c07de..815c5a48 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2802,10 +2802,9 @@ class ImagePut { static gdiplusStartup() { ImagePut.gdiplus++ - ; Startup gdiplus when counter goes from 0 -> 1. + ; Startup gdiplus when counter rises from 0 -> 1. if (ImagePut.gdiplus == 1) { - ; Startup gdiplus. DllCall("LoadLibrary", "str", "gdiplus") si := Buffer(A_PtrSize = 4 ? 16:24, 0) ; sizeof(GdiplusStartupInput) = 16, 24 NumPut("uint", 0x1, si) @@ -2822,11 +2821,10 @@ class ImagePut { if (ImagePut.gdiplus < 0) throw Error("Missing ImagePut.gdiplusStartup().") - ; Shutdown gdiplus when counter goes from 1 -> 0. + ; Shutdown gdiplus when counter falls from 1 -> 0. if (ImagePut.gdiplus == 0) { pToken := ImagePut.pToken - ; Shutdown gdiplus. DllCall("gdiplus\GdiplusShutdown", "ptr", pToken) DllCall("FreeLibrary", "ptr", DllCall("GetModuleHandle", "str", "gdiplus", "ptr")) From 00ec0e2fb41746c7f36352ec0c7f01e172735749 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 1 Jun 2022 14:42:01 -0400 Subject: [PATCH 272/492] lowercase control flow --- ImagePut (for v1).ahk | 12 ++++++------ ImagePut.ahk | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index d9f9cac2..18e89d03 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -921,7 +921,7 @@ class ImagePut { if (windows == 0) throw Exception("The hidden desktop window has not been initalized. Call ImagePutDesktop() first.") - Loop % windows + loop % windows hwnd := windows%A_Index% until DllCall("FindWindowEx", "ptr", hwnd, "ptr", 0, "str", "SHELLDLL_DefView", "ptr", 0) @@ -2244,7 +2244,7 @@ class ImagePut { ; Find the child window. WinGet windows, List, ahk_class WorkerW - Loop % windows + loop % windows hwnd := windows%A_Index% until DllCall("FindWindowEx", "ptr", hwnd, "ptr", 0, "str", "SHELLDLL_DefView", "ptr", 0) @@ -2951,7 +2951,7 @@ class ImageEqual extends ImagePut { throw Exception("Validation failed. Unable to access and clone the bitmap.") DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmapClone) - Goto Good_Ending + goto Good_Ending } ; If there are multiple images, compare each subsequent image to the first. @@ -2968,7 +2968,7 @@ class ImageEqual extends ImagePut { ; Compare the two images. if !this.BitmapEqual(pBitmap1, pBitmap2) - Goto Bad_Ending ; Exit the loop if the comparison failed. + goto Bad_Ending ; Exit the loop if the comparison failed. ; Cleanup the bitmap. DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap2) @@ -3023,7 +3023,7 @@ class ImageEqual extends ImagePut { ; I assume that instead of locking the stream, the clones lock the originals. pBitmap1 := pBitmap2 := 0 - Loop 2 + loop 2 if DllCall("gdiplus\GdipCloneBitmapAreaI" , "int", 0 , "int", 0 @@ -3044,7 +3044,7 @@ class ImageEqual extends ImagePut { VarSetCapacity(BitmapData2, 16+2*A_PtrSize) ; sizeof(BitmapData) = 24, 32 ; Transfer the pixels to a read-only buffer. The user can declare a PixelFormat. - Loop 2 + loop 2 DllCall("gdiplus\GdipBitmapLockBits" , "ptr", pBitmap%A_Index% , "ptr", &Rect diff --git a/ImagePut.ahk b/ImagePut.ahk index 815c5a48..4c35c4c6 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -921,7 +921,7 @@ class ImagePut { if (windows.length == 0) throw Error("The hidden desktop window has not been initalized. Call ImagePutDesktop() first.") - Loop windows.length + loop windows.length hwnd := windows[A_Index] until DllCall("FindWindowEx", "ptr", hwnd, "ptr", 0, "str", "SHELLDLL_DefView", "ptr", 0) @@ -2245,7 +2245,7 @@ class ImagePut { ; Find the child window. windows := WinGetList("ahk_class WorkerW") - Loop windows.length + loop windows.length hwnd := windows[A_Index] until DllCall("FindWindowEx", "ptr", hwnd, "ptr", 0, "str", "SHELLDLL_DefView", "ptr", 0) @@ -2952,7 +2952,7 @@ class ImageEqual extends ImagePut { throw Error("Validation failed. Unable to access and clone the bitmap.") DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmapClone) - Goto Good_Ending + goto Good_Ending } ; If there are multiple images, compare each subsequent image to the first. @@ -2969,7 +2969,7 @@ class ImageEqual extends ImagePut { ; Compare the two images. if !this.BitmapEqual(pBitmap1, pBitmap2) - Goto Bad_Ending ; Exit the loop if the comparison failed. + goto Bad_Ending ; Exit the loop if the comparison failed. ; Cleanup the bitmap. DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap2) @@ -3024,7 +3024,7 @@ class ImageEqual extends ImagePut { ; I assume that instead of locking the stream, the clones lock the originals. pBitmap1 := pBitmap2 := 0 - Loop 2 + loop 2 if DllCall("gdiplus\GdipCloneBitmapAreaI" , "int", 0 , "int", 0 @@ -3045,7 +3045,7 @@ class ImageEqual extends ImagePut { BitmapData2 := Buffer(16+2*A_PtrSize) ; sizeof(BitmapData) = 24, 32 ; Transfer the pixels to a read-only buffer. The user can declare a PixelFormat. - Loop 2 + loop 2 DllCall("gdiplus\GdipBitmapLockBits" , "ptr", pBitmap%A_Index% , "ptr", Rect From d721a541a0a336747646c1236fd875d034512927 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 1 Jun 2022 14:44:19 -0400 Subject: [PATCH 273/492] better comment --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 18e89d03..566318bf 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2980,7 +2980,7 @@ class ImageEqual extends ImagePut { this.gdiplusShutdown() return True - Bad_Ending: ; Turns out your best friend became super jealous of you and killed you in your sleep. + Bad_Ending: ; Things didn't turn out the way you expected yet everyone seems to be fine despite that. DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap2) DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap1) this.gdiplusShutdown() diff --git a/ImagePut.ahk b/ImagePut.ahk index 4c35c4c6..df105db1 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2981,7 +2981,7 @@ class ImageEqual extends ImagePut { this.gdiplusShutdown() return True - Bad_Ending: ; Turns out your best friend became super jealous of you and killed you in your sleep. + Bad_Ending: ; Things didn't turn out the way you expected yet everyone seems to be fine despite that. DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap2) DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap1) this.gdiplusShutdown() From 91e5506cc0a4b89a992a1f25443c975bf2950dfd Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 1 Jun 2022 14:45:20 -0400 Subject: [PATCH 274/492] Prefix labels with ImagePut --- ImagePut (for v1).ahk | 8 ++++---- ImagePut.ahk | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 566318bf..e9b34959 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2951,7 +2951,7 @@ class ImageEqual extends ImagePut { throw Exception("Validation failed. Unable to access and clone the bitmap.") DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmapClone) - goto Good_Ending + goto ImagePut_Good_Ending } ; If there are multiple images, compare each subsequent image to the first. @@ -2968,19 +2968,19 @@ class ImageEqual extends ImagePut { ; Compare the two images. if !this.BitmapEqual(pBitmap1, pBitmap2) - goto Bad_Ending ; Exit the loop if the comparison failed. + goto ImagePut_Bad_Ending ; Exit the loop if the comparison failed. ; Cleanup the bitmap. DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap2) } } - Good_Ending: ; After getting isekai'ed you somehow build a prosperous kingdom and rule the land. + ImagePut_Good_Ending: ; After getting isekai'ed you somehow build a prosperous kingdom and rule the land. DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap1) this.gdiplusShutdown() return True - Bad_Ending: ; Things didn't turn out the way you expected yet everyone seems to be fine despite that. + ImagePut_Bad_Ending: ; Things didn't turn out the way you expected yet everyone seems to be fine despite that. DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap2) DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap1) this.gdiplusShutdown() diff --git a/ImagePut.ahk b/ImagePut.ahk index df105db1..bade3de3 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2952,7 +2952,7 @@ class ImageEqual extends ImagePut { throw Error("Validation failed. Unable to access and clone the bitmap.") DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmapClone) - goto Good_Ending + goto ImagePut_Good_Ending } ; If there are multiple images, compare each subsequent image to the first. @@ -2969,19 +2969,19 @@ class ImageEqual extends ImagePut { ; Compare the two images. if !this.BitmapEqual(pBitmap1, pBitmap2) - goto Bad_Ending ; Exit the loop if the comparison failed. + goto ImagePut_Bad_Ending ; Exit the loop if the comparison failed. ; Cleanup the bitmap. DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap2) } } - Good_Ending: ; After getting isekai'ed you somehow build a prosperous kingdom and rule the land. + ImagePut_Good_Ending: ; After getting isekai'ed you somehow build a prosperous kingdom and rule the land. DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap1) this.gdiplusShutdown() return True - Bad_Ending: ; Things didn't turn out the way you expected yet everyone seems to be fine despite that. + ImagePut_Bad_Ending: ; Things didn't turn out the way you expected yet everyone seems to be fine despite that. DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap2) DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap1) this.gdiplusShutdown() From 33ddb7b8404d700633a61ecaef3765fb9ec835ed Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 1 Jun 2022 14:47:58 -0400 Subject: [PATCH 275/492] unnecessary double instantiation --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index e9b34959..c7e45610 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -3031,7 +3031,7 @@ class ImageEqual extends ImagePut { , "int", height%A_Index% , "int", format%A_Index% , "ptr", SourceBitmap%A_Index% - , "ptr*", pBitmap%A_Index%:=0) + , "ptr*", pBitmap%A_Index%) throw Exception("Cloning Bitmap" A_Index " failed.") ; struct RECT - https://referencesource.microsoft.com/#System.Drawing/commonui/System/Drawing/Rectangle.cs,32 diff --git a/ImagePut.ahk b/ImagePut.ahk index bade3de3..8cd1f895 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -3032,7 +3032,7 @@ class ImageEqual extends ImagePut { , "int", height%A_Index% , "int", format%A_Index% , "ptr", SourceBitmap%A_Index% - , "ptr*", &pBitmap%A_Index%:=0) + , "ptr*", &pBitmap%A_Index%) throw Error("Cloning Bitmap" A_Index " failed.") ; struct RECT - https://referencesource.microsoft.com/#System.Drawing/commonui/System/Drawing/Rectangle.cs,32 From b31e3c7527019c51deb2e014f9309b0e7159332c Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 1 Jun 2022 15:11:17 -0400 Subject: [PATCH 276/492] Switch case for Destroy() --- ImagePut (for v1).ahk | 49 +++++++++++++++++++---------------------- ImagePut.ahk | 51 ++++++++++++++++++++----------------------- 2 files changed, 47 insertions(+), 53 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index c7e45610..3fa71de0 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2869,29 +2869,29 @@ class ImagePut { } Destroy(type, image) { - if (type = "clipboard") { + switch type { + case "clipboard": if !DllCall("OpenClipboard", "ptr", A_ScriptHwnd) throw Exception("Clipboard could not be opened.") - try return DllCall("EmptyClipboard") - finally DllCall("CloseClipboard") - } + DllCall("EmptyClipboard") + DllCall("CloseClipboard") - if (type = "screenshot") - return DllCall("InvalidateRect", "ptr", 0, "ptr", 0, "int", 0) + case "screenshot": + DllCall("InvalidateRect", "ptr", 0, "ptr", 0, "int", 0) - if (type = "window") - return DllCall("DestroyWindow", "ptr", image) + case "window": + DllCall("DestroyWindow", "ptr", image) - if (type = "wallpaper") - return DllCall("SystemParametersInfo", "uint", SPI_SETDESKWALLPAPER := 0x14, "uint", 0, "ptr", 0, "uint", 2) + case "wallpaper": + DllCall("SystemParametersInfo", "uint", SPI_SETDESKWALLPAPER := 0x14, "uint", 0, "ptr", 0, "uint", 2) - if (type = "cursor") - return DllCall("SystemParametersInfo", "uint", SPI_SETCURSORS := 0x57, "uint", 0, "ptr", 0, "uint", 0) + case "cursor": + DllCall("SystemParametersInfo", "uint", SPI_SETCURSORS := 0x57, "uint", 0, "ptr", 0, "uint", 0) - if (type = "file") + case "file": FileDelete % image - if (type = "dc") { + case "dc": if (DllCall("GetObjectType", "ptr", image, "uint") == 3) { ; OBJ_DC hwnd := DllCall("WindowFromDC", "ptr", image, "ptr") DllCall("ReleaseDC", "ptr", hwnd, "ptr", image) @@ -2903,22 +2903,19 @@ class ImagePut { DllCall("DeleteObject", "ptr", hbm) DllCall("DeleteDC", "ptr", image) } - } - if (type = "hBitmap") - return DllCall("DeleteObject", "ptr", image) + case "hBitmap": + DllCall("DeleteObject", "ptr", image) - if (type = "hIcon") - return DllCall("DestroyIcon", "ptr", image) + case "hIcon": + DllCall("DestroyIcon", "ptr", image) - if (type = "bitmap") - return !DllCall("gdiplus\GdipDisposeImage", "ptr", image) + case "bitmap": + DllCall("gdiplus\GdipDisposeImage", "ptr", image) - if (type = "RandomAccessStream") or (type = "stream") - return !ObjRelease(image) - - if (type = "wicBitmap") - return ObjRelease(image) + case "RandomAccessStream", "stream", "wicBitmap": + ObjRelease(image) + } } } ; End of Destroy class. } ; End of ImagePut class. diff --git a/ImagePut.ahk b/ImagePut.ahk index 8cd1f895..49d82c99 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2870,29 +2870,29 @@ class ImagePut { } static Destroy(type, image) { - if (type = "clipboard") { + switch type { + case "clipboard": if !DllCall("OpenClipboard", "ptr", A_ScriptHwnd) - throw Error("Clipboard could not be opened.") - try return DllCall("EmptyClipboard") - finally DllCall("CloseClipboard") - } + throw Exception("Clipboard could not be opened.") + DllCall("EmptyClipboard") + DllCall("CloseClipboard") - if (type = "screenshot") - return DllCall("InvalidateRect", "ptr", 0, "ptr", 0, "int", 0) + case "screenshot": + DllCall("InvalidateRect", "ptr", 0, "ptr", 0, "int", 0) - if (type = "window") - return DllCall("DestroyWindow", "ptr", image) + case "window": + DllCall("DestroyWindow", "ptr", image) - if (type = "wallpaper") - return DllCall("SystemParametersInfo", "uint", SPI_SETDESKWALLPAPER := 0x14, "uint", 0, "ptr", 0, "uint", 2) + case "wallpaper": + DllCall("SystemParametersInfo", "uint", SPI_SETDESKWALLPAPER := 0x14, "uint", 0, "ptr", 0, "uint", 2) - if (type = "cursor") - return DllCall("SystemParametersInfo", "uint", SPI_SETCURSORS := 0x57, "uint", 0, "ptr", 0, "uint", 0) + case "cursor": + DllCall("SystemParametersInfo", "uint", SPI_SETCURSORS := 0x57, "uint", 0, "ptr", 0, "uint", 0) - if (type = "file") + case "file": FileDelete image - if (type = "dc") { + case "dc": if (DllCall("GetObjectType", "ptr", image, "uint") == 3) { ; OBJ_DC hwnd := DllCall("WindowFromDC", "ptr", image, "ptr") DllCall("ReleaseDC", "ptr", hwnd, "ptr", image) @@ -2904,22 +2904,19 @@ class ImagePut { DllCall("DeleteObject", "ptr", hbm) DllCall("DeleteDC", "ptr", image) } - } - if (type = "hBitmap") - return DllCall("DeleteObject", "ptr", image) + case "hBitmap": + DllCall("DeleteObject", "ptr", image) - if (type = "hIcon") - return DllCall("DestroyIcon", "ptr", image) + case "hIcon": + DllCall("DestroyIcon", "ptr", image) - if (type = "bitmap") - return !DllCall("gdiplus\GdipDisposeImage", "ptr", image) + case "bitmap": + DllCall("gdiplus\GdipDisposeImage", "ptr", image) - if (type = "RandomAccessStream") or (type = "stream") - return !ObjRelease(image) - - if (type = "wicBitmap") - return ObjRelease(image) + case "RandomAccessStream", "stream", "wicBitmap": + ObjRelease(image) + } } } ; End of Destroy class. } ; End of ImagePut class. From 2f918633d732d6677e31705378b5168e9b5456ce Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 2 Jun 2022 16:59:56 -0400 Subject: [PATCH 277/492] Try-finally to avoid intermediate values --- ImagePut (for v1).ahk | 5 ++--- ImagePut.ahk | 7 +++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 3fa71de0..b875c36f 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1113,9 +1113,8 @@ class ImagePut { DllCall(IClosable_Close := NumGet(NumGet(Close+0)+6*A_PtrSize), "ptr", Close) ObjRelease(Close) } - refcount := ObjRelease(Object) - Object := "" - return refcount + try return ObjRelease(Object) + finally Object := "" } } diff --git a/ImagePut.ahk b/ImagePut.ahk index 49d82c99..d3ff6d8f 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1113,9 +1113,8 @@ class ImagePut { ComCall(IClosable_Close := 6, Close) Close := "" } - refcount := ObjRelease(Object) - Object := "" - return refcount + try return ObjRelease(Object) + finally Object := "" } } @@ -2873,7 +2872,7 @@ class ImagePut { switch type { case "clipboard": if !DllCall("OpenClipboard", "ptr", A_ScriptHwnd) - throw Exception("Clipboard could not be opened.") + throw Error("Clipboard could not be opened.") DllCall("EmptyClipboard") DllCall("CloseClipboard") From a6b13dc4e6feb420766e809acb7b789d0c9bfcbb Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 13 Jun 2022 21:30:47 -0400 Subject: [PATCH 278/492] v2 Close each window individually --- ImagePut (for v1).ahk | 16 +++++++++------- ImagePut.ahk | 16 +++++++++------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index b875c36f..f8b3960c 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2030,10 +2030,6 @@ class ImagePut { (style == "") && style := WS_POPUP | WS_VISIBLE (styleEx == "") && styleEx := WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_EX_LAYERED - ; Prevent the script from exiting early. - void := ObjBindMethod({}, {}) - Hotkey % "^+F12", % void, On - ; Get Bitmap width and height. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) @@ -2202,10 +2198,16 @@ class ImagePut { WindowProc(uMsg, wParam, lParam) { Critical ; Thread must never be interrupted. hwnd := this + ; Prevent the script from exiting early. + static void := ObjBindMethod({}, {}) + + ; WM_CREATE + if (uMsg = 0x1) + Hotkey % "^+F12", % void, On + ; WM_DESTROY - if (uMsg = 0x2) { - Hotkey % "^+F12", Off - } + if (uMsg = 0x2) + Hotkey % "^+F12", % void, Off ; Cannot disable, does nothing ; WM_LBUTTONDOWN if (uMsg = 0x201) { diff --git a/ImagePut.ahk b/ImagePut.ahk index d3ff6d8f..bd53eb9e 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2031,10 +2031,6 @@ class ImagePut { (style == "") && style := WS_POPUP | WS_VISIBLE (styleEx == "") && styleEx := WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_EX_LAYERED - ; Prevent the script from exiting early. - Persistent(True) - - ; Get Bitmap width and height. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) @@ -2203,10 +2199,16 @@ class ImagePut { WindowProc(hwnd, uMsg, wParam, lParam) { Critical ; Thread must never be interrupted. + ; Prevent the script from exiting early. + static active_windows := Persistent() + + ; WM_CREATE + if (uMsg = 0x1) + return Persistent(++active_windows) + ; WM_DESTROY - if (uMsg = 0x2) { - return Persistent(False) - } + if (uMsg = 0x2) + return Persistent(--active_windows) ; WM_LBUTTONDOWN if (uMsg = 0x201) { From 9a52b8020c56665705a5e578ba1d73f3ae6e9f19 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 13 Jun 2022 22:05:39 -0400 Subject: [PATCH 279/492] DestroyWindow should return 0 in WindowProc --- ImagePut (for v1).ahk | 3 ++- ImagePut.ahk | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index f8b3960c..ad0cd311 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2220,7 +2220,8 @@ class ImagePut { if (uMsg = 0x205) { parent := DllCall("GetParent", "ptr", hwnd, "ptr") hwnd := (parent != A_ScriptHwnd && parent != 0) ? parent : hwnd - return DllCall("DestroyWindow", "ptr", hwnd) + DllCall("DestroyWindow", "ptr", hwnd) + return 0 } return DllCall("DefWindowProc", "ptr", hwnd, "uint", uMsg, "uptr", wParam, "ptr", lParam, "ptr") diff --git a/ImagePut.ahk b/ImagePut.ahk index bd53eb9e..f5e14876 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2221,7 +2221,8 @@ class ImagePut { if (uMsg = 0x205) { parent := DllCall("GetParent", "ptr", hwnd, "ptr") hwnd := (parent != A_ScriptHwnd && parent != 0) ? parent : hwnd - return DllCall("DestroyWindow", "ptr", hwnd) + DllCall("DestroyWindow", "ptr", hwnd) + return 0 } return DllCall("DefWindowProc", "ptr", hwnd, "uint", uMsg, "uptr", wParam, "ptr", lParam, "ptr") From 485a334fb0c16ed12bfcbc2de7d5dfd26669f601 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 13 Jun 2022 22:13:37 -0400 Subject: [PATCH 280/492] small comment --- ImagePut (for v1).ahk | 1 + ImagePut.ahk | 1 + 2 files changed, 2 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index ad0cd311..b8f5c9dd 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2224,6 +2224,7 @@ class ImagePut { return 0 } + ; Must return return DllCall("DefWindowProc", "ptr", hwnd, "uint", uMsg, "uptr", wParam, "ptr", lParam, "ptr") } diff --git a/ImagePut.ahk b/ImagePut.ahk index f5e14876..a959ebcf 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2225,6 +2225,7 @@ class ImagePut { return 0 } + ; Must return return DllCall("DefWindowProc", "ptr", hwnd, "uint", uMsg, "uptr", wParam, "ptr", lParam, "ptr") } } From 4d0f56969230653ddb2c51220b8004024f7cdcf7 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 13 Jun 2022 23:05:47 -0400 Subject: [PATCH 281/492] Unused gdip image format line --- ImagePut (for v1).ahk | 2 -- ImagePut.ahk | 2 -- 2 files changed, 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index b8f5c9dd..04143073 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2072,8 +2072,6 @@ class ImagePut { hbm := DllCall("CreateDIBSection", "ptr", hdc, "ptr", &bi, "uint", 0, "ptr*", pBits:=0, "ptr", 0, "uint", 0, "ptr") obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") - DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", pBitmap, "int*", format:=0) - ; Case 1: Image is not scaled. if (s = 1) { ; Transfer data from source pBitmap to an hBitmap manually. diff --git a/ImagePut.ahk b/ImagePut.ahk index a959ebcf..38f40523 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2073,8 +2073,6 @@ class ImagePut { hbm := DllCall("CreateDIBSection", "ptr", hdc, "ptr", bi, "uint", 0, "ptr*", &pBits:=0, "ptr", 0, "uint", 0, "ptr") obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") - DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", pBitmap, "int*", &format:=0) - ; Case 1: Image is not scaled. if (s = 1) { ; Transfer data from source pBitmap to an hBitmap manually. From 039e24a1957bfcce14387a965527bc3c6ac2349a Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 13 Jun 2022 23:16:49 -0400 Subject: [PATCH 282/492] Prevent Taskbar Overlay of ImageShow --- ImagePut (for v1).ahk | 5 +++-- ImagePut.ahk | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 04143073..cd219bf4 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -127,7 +127,7 @@ ImagePutWindow(image, title := "", pos := "", style := 0x82C80000, styleEx := 0x ; style - Window Style | uint -> WS_VISIBLE ; styleEx - Window Extended Style | uint -> WS_EX_LAYERED ; parent - Window Parent | ptr -> hwnd -ImageShow(image, title := "", pos := "", style := 0x90000000, styleEx := 0x80088, parent := "") { +ImageShow(image, title := "", pos := "", style := 0x90000000, styleEx := 0x8080088, parent := "") { return ImagePut("show", image, title, pos, style, styleEx, parent) } @@ -2016,7 +2016,7 @@ class ImagePut { return hwnd } - show(pBitmap, title := "", pos := "", style := 0x90000000, styleEx := 0x80088, parent := "") { + show(pBitmap, title := "", pos := "", style := 0x90000000, styleEx := 0x8080088, parent := "") { ; Window Styles - https://docs.microsoft.com/en-us/windows/win32/winmsg/window-styles WS_POPUP := 0x80000000 ; Allow small windows. WS_VISIBLE := 0x10000000 ; Show on creation. @@ -2025,6 +2025,7 @@ class ImagePut { WS_EX_TOPMOST := 0x8 ; Always on top. WS_EX_TOOLWINDOW := 0x80 ; Hides from Alt+Tab menu. Removes small icon. WS_EX_LAYERED := 0x80000 ; For UpdateLayeredWindow. + WS_EX_NOACTIVATE := 0x8000000 ; Prevent taskbar overlay. ; Default styles can be overwritten by previous functions. (style == "") && style := WS_POPUP | WS_VISIBLE diff --git a/ImagePut.ahk b/ImagePut.ahk index 38f40523..4d630e63 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -127,7 +127,7 @@ ImagePutWindow(image, title := "", pos := "", style := 0x82C80000, styleEx := 0x ; style - Window Style | uint -> WS_VISIBLE ; styleEx - Window Extended Style | uint -> WS_EX_LAYERED ; parent - Window Parent | ptr -> hwnd -ImageShow(image, title := "", pos := "", style := 0x90000000, styleEx := 0x80088, parent := "") { +ImageShow(image, title := "", pos := "", style := 0x90000000, styleEx := 0x8080088, parent := "") { return ImagePut("show", image, title, pos, style, styleEx, parent) } @@ -2017,7 +2017,7 @@ class ImagePut { return hwnd } - static show(pBitmap, title := "", pos := "", style := 0x90000000, styleEx := 0x80088, parent := "") { + static show(pBitmap, title := "", pos := "", style := 0x90000000, styleEx := 0x8080088, parent := "") { ; Window Styles - https://docs.microsoft.com/en-us/windows/win32/winmsg/window-styles WS_POPUP := 0x80000000 ; Allow small windows. WS_VISIBLE := 0x10000000 ; Show on creation. @@ -2026,6 +2026,7 @@ class ImagePut { WS_EX_TOPMOST := 0x8 ; Always on top. WS_EX_TOOLWINDOW := 0x80 ; Hides from Alt+Tab menu. Removes small icon. WS_EX_LAYERED := 0x80000 ; For UpdateLayeredWindow. + WS_EX_NOACTIVATE := 0x8000000 ; Prevent taskbar overlay. ; Default styles can be overwritten by previous functions. (style == "") && style := WS_POPUP | WS_VISIBLE From 5a59bb6f62c521c319f766e5ed135a2764fae3ed Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 13 Jun 2022 23:30:41 -0400 Subject: [PATCH 283/492] comment --- ImagePut (for v1).ahk | 1 + ImagePut.ahk | 1 + 2 files changed, 2 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index cd219bf4..76845b46 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2011,6 +2011,7 @@ class ImagePut { ; A layered child window is only available on Windows 8+. this.show(pBitmap, title, [0, 0, w, h], WS_CHILD | WS_VISIBLE, WS_EX_LAYERED, hwnd) + ; Prevent empty windows from showing. DllCall("ShowWindow", "ptr", hwnd, "int", 1) return hwnd diff --git a/ImagePut.ahk b/ImagePut.ahk index 4d630e63..55dbf399 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2012,6 +2012,7 @@ class ImagePut { ; A layered child window is only available on Windows 8+. this.show(pBitmap, title, [0, 0, w, h], WS_CHILD | WS_VISIBLE, WS_EX_LAYERED, hwnd) + ; Prevent empty windows from showing. DllCall("ShowWindow", "ptr", hwnd, "int", 1) return hwnd From 5cf33f66f0b9fd54769748de6c3f655f8d25bc50 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 14 Jun 2022 15:29:02 -0400 Subject: [PATCH 284/492] Change put_dc to be more like put_hbitmap --- ImagePut (for v1).ahk | 40 +++++++++++++++++++++++++++++++++++++--- ImagePut.ahk | 40 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 74 insertions(+), 6 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 76845b46..87657d75 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2541,11 +2541,45 @@ class ImagePut { } put_dc(pBitmap, alpha := "") { - ; This may seem strange, but the hBitmap is selected onto the device context, - ; and therefore cannot be deleted. In addition, the stock bitmap can never be leaked. + ; Revert to built in functionality if a replacement color is declared. + if (alpha != "") { ; This built-in version is about 25% slower and also preserves transparency. + DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", "ptr", pBitmap, "ptr*", hbm:=0, "uint", alpha) + return hbm + } + + ; Get Bitmap width and height. + DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) + DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) + + ; Convert the source pBitmap into a hBitmap manually. + ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") - hbm := this.put_hBitmap(pBitmap, alpha) + VarSetCapacity(bi, 40, 0) ; sizeof(bi) = 40 + NumPut( 40, bi, 0, "uint") ; Size + NumPut( width, bi, 4, "uint") ; Width + NumPut( -height, bi, 8, "int") ; Height - Negative so (0, 0) is top-left. + NumPut( 1, bi, 12, "ushort") ; Planes + NumPut( 32, bi, 14, "ushort") ; BitCount / BitsPerPixel + hbm := DllCall("CreateDIBSection", "ptr", hdc, "ptr", &bi, "uint", 0, "ptr*", pBits:=0, "ptr", 0, "uint", 0, "ptr") obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") + + ; Transfer data from source pBitmap to an hBitmap manually. + VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 + NumPut( width, Rect, 8, "uint") ; Width + NumPut( height, Rect, 12, "uint") ; Height + VarSetCapacity(BitmapData, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + NumPut( 4 * width, BitmapData, 8, "int") ; Stride + NumPut( pBits, BitmapData, 16, "ptr") ; Scan0 + DllCall("gdiplus\GdipBitmapLockBits" + , "ptr", pBitmap + , "ptr", &Rect + , "uint", 5 ; ImageLockMode.UserInputBuffer | ImageLockMode.ReadOnly + , "int", 0xE200B ; Format32bppPArgb + , "ptr", &BitmapData) ; Contains the pointer (pBits) to the hbm. + DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", &BitmapData) + + ; This may seem strange, but the hBitmap is selected onto the device context, + ; and therefore cannot be deleted. In addition, the stock bitmap can never be leaked. return hdc } diff --git a/ImagePut.ahk b/ImagePut.ahk index 55dbf399..2e34bde1 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2542,11 +2542,45 @@ class ImagePut { } static put_dc(pBitmap, alpha := "") { - ; This may seem strange, but the hBitmap is selected onto the device context, - ; and therefore cannot be deleted. In addition, the stock bitmap can never be leaked. + ; Revert to built in functionality if a replacement color is declared. + if (alpha != "") { ; This built-in version is about 25% slower and also preserves transparency. + DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", "ptr", pBitmap, "ptr*", &hbm:=0, "uint", alpha) + return hbm + } + + ; Get Bitmap width and height. + DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) + DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) + + ; Convert the source pBitmap into a hBitmap manually. + ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") - hbm := this.put_hBitmap(pBitmap, alpha) + bi := Buffer(40, 0) ; sizeof(bi) = 40 + NumPut( "uint", 40, bi, 0) ; Size + NumPut( "int", width, bi, 4) ; Width + NumPut( "int", -height, bi, 8) ; Height - Negative so (0, 0) is top-left. + NumPut("ushort", 1, bi, 12) ; Planes + NumPut("ushort", 32, bi, 14) ; BitCount / BitsPerPixel + hbm := DllCall("CreateDIBSection", "ptr", hdc, "ptr", bi, "uint", 0, "ptr*", &pBits:=0, "ptr", 0, "uint", 0, "ptr") obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") + + ; Transfer data from source pBitmap to an hBitmap manually. + Rect := Buffer(16, 0) ; sizeof(Rect) = 16 + NumPut( "uint", width, Rect, 8) ; Width + NumPut( "uint", height, Rect, 12) ; Height + BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + NumPut( "int", 4 * width, BitmapData, 8) ; Stride + NumPut( "ptr", pBits, BitmapData, 16) ; Scan0 + DllCall("gdiplus\GdipBitmapLockBits" + , "ptr", pBitmap + , "ptr", Rect + , "uint", 5 ; ImageLockMode.UserInputBuffer | ImageLockMode.ReadOnly + , "int", 0xE200B ; Format32bppPArgb + , "ptr", BitmapData) ; Contains the pointer (pBits) to the hbm. + DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", BitmapData) + + ; This may seem strange, but the hBitmap is selected onto the device context, + ; and therefore cannot be deleted. In addition, the stock bitmap can never be leaked. return hdc } From 390732a04cb381fda3a24155186e939f31ba128e Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 14 Jun 2022 16:56:52 -0400 Subject: [PATCH 285/492] Animate GIFs --- ImagePut (for v1).ahk | 63 ++++++++++++++++++++++++++++++++++++++++++- ImagePut.ahk | 63 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 124 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 87657d75..249bfed8 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2154,6 +2154,15 @@ class ImagePut { DllCall("DeleteObject", "ptr", hbm) DllCall("DeleteDC", "ptr", hdc) + ; For multiple frames, send WM_APP to WindowProc to render GIFs. + DllCall("Gdiplus\GdipImageGetFrameDimensionsCount", "ptr", pBitmap, "uint*", dims:=0) + DllCall("Gdiplus\GdipImageGetFrameDimensionsList", "ptr", pBitmap, "ptr", &dimIDs := VarSetCapacity(dimIDs, 16*dims), "uint", dims) + DllCall("Gdiplus\GdipImageGetFrameCount", "ptr", pBitmap, "ptr", &dimIDs, "uint*", frames:=0) + if (frames > 1) { + DllCall("gdiplus\GdipCloneImage", "ptr", pBitmap, "ptr*", pBitmapClone:=0) + DllCall("PostMessage", "ptr", hwnd, "uint", 0x8000, "uptr", -1, "ptr", pBitmapClone) + } + return hwnd } @@ -2196,7 +2205,6 @@ class ImagePut { } ; Define window behavior. WindowProc(uMsg, wParam, lParam) { - Critical ; Thread must never be interrupted. hwnd := this ; Prevent the script from exiting early. static void := ObjBindMethod({}, {}) @@ -2224,6 +2232,59 @@ class ImagePut { return 0 } + ; WM_APP - Animate GIFs + if (uMsg = 0x8000) { + Critical ; Thread must never be interrupted. + pBitmap := lParam + frame := wParam + 1 + + ; If the window is destroyed, dispose the held bitmap. + if not DllCall("IsWindow", "ptr", hwnd) + return DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + + ; Get the next frame and delay. + DllCall("gdiplus\GdipGetPropertyItemSize", "ptr", pBitmap, "uint", 0x5100, "uint*", ItemSize:=0) ; PropertyTagFrameDelay + DllCall("gdiplus\GdipGetPropertyItem" , "ptr", pBitmap, "uint", 0x5100, "uint", ItemSize, "ptr", &Item := VarSetCapacity(Item, ItemSize)) + frames := NumGet(Item, 4, "uint") // 4 ; Max frames + delays := NumGet(Item, 8 + A_PtrSize, "ptr") ; Array of delays + frame := mod(frame, frames) ; Loop to first frame + delay := Max(10 * NumGet(delays+0, frame*4, "uint"), 10) ; Minimum delay is 10ms + (delay == 10) && delay := 100 ; Emulate behavior of browser setting 10 ms to 100 ms. + + ; Async the next frame as soon as possible to prevent rendering lag. + pWndProc := RegisterCallback(ImagePut.WindowProc,,, &ImagePut) + next_frame := Func("DllCall").bind(pWndProc, "ptr", hwnd, "uint", uMsg, "uptr", frame, "ptr", pBitmap) + SetTimer % next_frame, % -1 * delay + + ; Select frame to show. + DllCall("Gdiplus\GdipImageGetFrameDimensionsCount", "ptr", pBitmap, "uint*", dims:=0) + DllCall("Gdiplus\GdipImageGetFrameDimensionsList", "ptr", pBitmap, "ptr", &dimIDs := VarSetCapacity(dimIDs, 16*dims), "uint", dims) + DllCall("gdiplus\GdipImageSelectActiveFrame", "ptr", pBitmap, "ptr", &dimIDs, "uint", frame) + + ; Get Bitmap width and height. + DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) + DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) + + ; Render to window. Using put_dc shortens the code. + hdc := ImagePut.put_dc(pBitmap) + DllCall("UpdateLayeredWindow" + , "ptr", hwnd ; hWnd + , "ptr", 0 ; hdcDst + , "ptr", 0 ; *pptDst + ,"uint64*", width | height << 32 ; *psize + , "ptr", hdc ; hdcSrc + , "int64*", 0 ; *pptSrc + , "uint", 0 ; crKey + , "uint*", 0xFF << 16 | 0x01 << 24 ; *pblend + , "uint", 2) ; dwFlags + + ; Cleanup the hBitmap and device contexts. + obm := DllCall("CreateBitmap", "int", 0, "int", 0, "uint", 1, "uint", 1, "ptr", 0, "ptr") + hbm := DllCall("SelectObject", "ptr", hdc, "ptr", obm, "ptr") + DllCall("DeleteObject", "ptr", hbm) + DllCall("DeleteDC", "ptr", hdc) + } + ; Must return return DllCall("DefWindowProc", "ptr", hwnd, "uint", uMsg, "uptr", wParam, "ptr", lParam, "ptr") } diff --git a/ImagePut.ahk b/ImagePut.ahk index 2e34bde1..405f0087 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2155,6 +2155,15 @@ class ImagePut { DllCall("DeleteObject", "ptr", hbm) DllCall("DeleteDC", "ptr", hdc) + ; For multiple frames, send WM_APP to WindowProc to render GIFs. + DllCall("Gdiplus\GdipImageGetFrameDimensionsCount", "ptr", pBitmap, "uint*", &dims:=0) + DllCall("Gdiplus\GdipImageGetFrameDimensionsList", "ptr", pBitmap, "ptr", dimIDs := Buffer(16*dims), "uint", dims) + DllCall("Gdiplus\GdipImageGetFrameCount", "ptr", pBitmap, "ptr", dimIDs, "uint*", &frames:=0) + if (frames > 1) { + DllCall("gdiplus\GdipCloneImage", "ptr", pBitmap, "ptr*", &pBitmapClone:=0) + DllCall("PostMessage", "ptr", hwnd, "uint", 0x8000, "uptr", -1, "ptr", pBitmapClone) + } + return hwnd } @@ -2197,7 +2206,6 @@ class ImagePut { ; Define window behavior. WindowProc(hwnd, uMsg, wParam, lParam) { - Critical ; Thread must never be interrupted. ; Prevent the script from exiting early. static active_windows := Persistent() @@ -2225,6 +2233,59 @@ class ImagePut { return 0 } + ; WM_APP - Animate GIFs + if (uMsg = 0x8000) { + Critical ; Thread must never be interrupted. + pBitmap := lParam + frame := wParam + 1 + + ; If the window is destroyed, dispose the held bitmap. + if not DllCall("IsWindow", "ptr", hwnd) + return DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + + ; Get the next frame and delay. + DllCall("gdiplus\GdipGetPropertyItemSize", "ptr", pBitmap, "uint", 0x5100, "uint*", &ItemSize:=0) ; PropertyTagFrameDelay + DllCall("gdiplus\GdipGetPropertyItem" , "ptr", pBitmap, "uint", 0x5100, "uint", ItemSize, "ptr", Item := Buffer(ItemSize)) + frames := NumGet(Item, 4, "uint") // 4 ; Max frames + delays := NumGet(Item, 8 + A_PtrSize, "ptr") ; Array of delays + frame := mod(frame, frames) ; Loop to first frame + delay := Max(10 * NumGet(delays, frame*4, "uint"), 10) ; Minimum delay is 10ms + (delay == 10) && delay := 100 ; Emulate behavior of browser setting 10 ms to 100 ms. + + ; Async the next frame as soon as possible to prevent rendering lag. + SetTimer WindowProc.bind(hwnd, uMsg, frame, pBitmap), -1 * delay + + + + ; Select frame to show. + DllCall("gdiplus\GdipImageGetFrameDimensionsCount", "ptr", pBitmap, "uint*", &dims:=0) + DllCall("gdiplus\GdipImageGetFrameDimensionsList", "ptr", pBitmap, "ptr", dimIDs := Buffer(16*dims), "uint", dims) + DllCall("gdiplus\GdipImageSelectActiveFrame", "ptr", pBitmap, "ptr", dimIDs, "uint", frame) + + ; Get Bitmap width and height. + DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) + DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) + + ; Render to window. Using put_dc shortens the code. + hdc := this.put_dc(pBitmap) + DllCall("UpdateLayeredWindow" + , "ptr", hwnd ; hWnd + , "ptr", 0 ; hdcDst + , "ptr", 0 ; *pptDst + ,"uint64*", width | height << 32 ; *psize + , "ptr", hdc ; hdcSrc + , "int64*", 0 ; *pptSrc + , "uint", 0 ; crKey + , "uint*", 0xFF << 16 | 0x01 << 24 ; *pblend + , "uint", 2) ; dwFlags + + ; Cleanup the hBitmap and device contexts. + obm := DllCall("CreateBitmap", "int", 0, "int", 0, "uint", 1, "uint", 1, "ptr", 0, "ptr") + hbm := DllCall("SelectObject", "ptr", hdc, "ptr", obm, "ptr") + DllCall("DeleteObject", "ptr", hbm) + DllCall("DeleteDC", "ptr", hdc) + } + ; Must return return DllCall("DefWindowProc", "ptr", hwnd, "uint", uMsg, "uptr", wParam, "ptr", lParam, "ptr") } From 144c11107b271c9b812c7ff6da25cefe0ee59cf1 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 14 Jun 2022 17:04:03 -0400 Subject: [PATCH 286/492] thanks --- ImagePut (for v1).ahk | 2 ++ ImagePut.ahk | 2 ++ 2 files changed, 4 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 249bfed8..f2f49e18 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2234,6 +2234,8 @@ class ImagePut { ; WM_APP - Animate GIFs if (uMsg = 0x8000) { + ; Thanks Teadrinker - https://www.autohotkey.com/boards/viewtopic.php?f=76&t=83358 + Critical ; Thread must never be interrupted. pBitmap := lParam frame := wParam + 1 diff --git a/ImagePut.ahk b/ImagePut.ahk index 405f0087..5e2912bd 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2235,6 +2235,8 @@ class ImagePut { ; WM_APP - Animate GIFs if (uMsg = 0x8000) { + ; Thanks Teadrinker - https://www.autohotkey.com/boards/viewtopic.php?f=76&t=83358 + Critical ; Thread must never be interrupted. pBitmap := lParam frame := wParam + 1 From d02df31fb8bab9c6a0cef75af3427743e4f09624 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 14 Jun 2022 17:09:00 -0400 Subject: [PATCH 287/492] Revert NoActivate as default --- ImagePut (for v1).ahk | 5 ++--- ImagePut.ahk | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index f2f49e18..e94f6013 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -127,7 +127,7 @@ ImagePutWindow(image, title := "", pos := "", style := 0x82C80000, styleEx := 0x ; style - Window Style | uint -> WS_VISIBLE ; styleEx - Window Extended Style | uint -> WS_EX_LAYERED ; parent - Window Parent | ptr -> hwnd -ImageShow(image, title := "", pos := "", style := 0x90000000, styleEx := 0x8080088, parent := "") { +ImageShow(image, title := "", pos := "", style := 0x90000000, styleEx := 0x80088, parent := "") { return ImagePut("show", image, title, pos, style, styleEx, parent) } @@ -2017,7 +2017,7 @@ class ImagePut { return hwnd } - show(pBitmap, title := "", pos := "", style := 0x90000000, styleEx := 0x8080088, parent := "") { + show(pBitmap, title := "", pos := "", style := 0x90000000, styleEx := 0x80088, parent := "") { ; Window Styles - https://docs.microsoft.com/en-us/windows/win32/winmsg/window-styles WS_POPUP := 0x80000000 ; Allow small windows. WS_VISIBLE := 0x10000000 ; Show on creation. @@ -2026,7 +2026,6 @@ class ImagePut { WS_EX_TOPMOST := 0x8 ; Always on top. WS_EX_TOOLWINDOW := 0x80 ; Hides from Alt+Tab menu. Removes small icon. WS_EX_LAYERED := 0x80000 ; For UpdateLayeredWindow. - WS_EX_NOACTIVATE := 0x8000000 ; Prevent taskbar overlay. ; Default styles can be overwritten by previous functions. (style == "") && style := WS_POPUP | WS_VISIBLE diff --git a/ImagePut.ahk b/ImagePut.ahk index 5e2912bd..30ec1f76 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -127,7 +127,7 @@ ImagePutWindow(image, title := "", pos := "", style := 0x82C80000, styleEx := 0x ; style - Window Style | uint -> WS_VISIBLE ; styleEx - Window Extended Style | uint -> WS_EX_LAYERED ; parent - Window Parent | ptr -> hwnd -ImageShow(image, title := "", pos := "", style := 0x90000000, styleEx := 0x8080088, parent := "") { +ImageShow(image, title := "", pos := "", style := 0x90000000, styleEx := 0x80088, parent := "") { return ImagePut("show", image, title, pos, style, styleEx, parent) } @@ -2018,7 +2018,7 @@ class ImagePut { return hwnd } - static show(pBitmap, title := "", pos := "", style := 0x90000000, styleEx := 0x8080088, parent := "") { + static show(pBitmap, title := "", pos := "", style := 0x90000000, styleEx := 0x80088, parent := "") { ; Window Styles - https://docs.microsoft.com/en-us/windows/win32/winmsg/window-styles WS_POPUP := 0x80000000 ; Allow small windows. WS_VISIBLE := 0x10000000 ; Show on creation. @@ -2027,7 +2027,6 @@ class ImagePut { WS_EX_TOPMOST := 0x8 ; Always on top. WS_EX_TOOLWINDOW := 0x80 ; Hides from Alt+Tab menu. Removes small icon. WS_EX_LAYERED := 0x80000 ; For UpdateLayeredWindow. - WS_EX_NOACTIVATE := 0x8000000 ; Prevent taskbar overlay. ; Default styles can be overwritten by previous functions. (style == "") && style := WS_POPUP | WS_VISIBLE From 9c32cd3ad768f48aa1697765ca3c5ed7f3a3abba Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 14 Jun 2022 17:18:56 -0400 Subject: [PATCH 288/492] v1.8 --- ImagePut (for v1).ahk | 4 ++-- ImagePut.ahk | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index e94f6013..6951570f 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2,8 +2,8 @@ ; License: MIT License ; Author: Edison Hua (iseahound) ; Github: https://github.com/iseahound/ImagePut -; Date: 2022-04-24 -; Version: 1.7.0 +; Date: 2022-06-14 +; Version: 1.8.0 #Requires AutoHotkey v1.1.33+ diff --git a/ImagePut.ahk b/ImagePut.ahk index 30ec1f76..1343bff2 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2,8 +2,8 @@ ; License: MIT License ; Author: Edison Hua (iseahound) ; Github: https://github.com/iseahound/ImagePut -; Date: 2022-04-24 -; Version: 1.7.0 +; Date: 2022-06-14 +; Version: 1.8.0 #Requires AutoHotkey v2.0-beta.3+ From cdf59611dd9b7a39f32f6a16e88898f83c053efa Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 14 Jun 2022 21:37:50 -0400 Subject: [PATCH 289/492] comment --- ImagePut (for v1).ahk | 4 +++- ImagePut.ahk | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 6951570f..50cf1911 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2250,7 +2250,9 @@ class ImagePut { delays := NumGet(Item, 8 + A_PtrSize, "ptr") ; Array of delays frame := mod(frame, frames) ; Loop to first frame delay := Max(10 * NumGet(delays+0, frame*4, "uint"), 10) ; Minimum delay is 10ms - (delay == 10) && delay := 100 ; Emulate behavior of browser setting 10 ms to 100 ms. + + ; Emulate behavior of setting 10 ms to 100 ms. + (delay == 10) && delay := 100 ; See: https://www.biphelps.com/blog/The-Fastest-GIF-Does-Not-Exist ; Async the next frame as soon as possible to prevent rendering lag. pWndProc := RegisterCallback(ImagePut.WindowProc,,, &ImagePut) diff --git a/ImagePut.ahk b/ImagePut.ahk index 1343bff2..27ecafa2 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2251,7 +2251,9 @@ class ImagePut { delays := NumGet(Item, 8 + A_PtrSize, "ptr") ; Array of delays frame := mod(frame, frames) ; Loop to first frame delay := Max(10 * NumGet(delays, frame*4, "uint"), 10) ; Minimum delay is 10ms - (delay == 10) && delay := 100 ; Emulate behavior of browser setting 10 ms to 100 ms. + + ; Emulate behavior of setting 10 ms to 100 ms. + (delay == 10) && delay := 100 ; See: https://www.biphelps.com/blog/The-Fastest-GIF-Does-Not-Exist ; Async the next frame as soon as possible to prevent rendering lag. SetTimer WindowProc.bind(hwnd, uMsg, frame, pBitmap), -1 * delay From ea6e91b30e92e1bc0b56d6cbfe9aeeb95aa7efaf Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 15 Jun 2022 14:07:44 -0400 Subject: [PATCH 290/492] Accurate GIF animation delay --- ImagePut (for v1).ahk | 71 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 56 insertions(+), 15 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 50cf1911..33fb43d4 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2153,11 +2153,20 @@ class ImagePut { DllCall("DeleteObject", "ptr", hbm) DllCall("DeleteDC", "ptr", hdc) - ; For multiple frames, send WM_APP to WindowProc to render GIFs. + ; Check for multiple frames. DllCall("Gdiplus\GdipImageGetFrameDimensionsCount", "ptr", pBitmap, "uint*", dims:=0) DllCall("Gdiplus\GdipImageGetFrameDimensionsList", "ptr", pBitmap, "ptr", &dimIDs := VarSetCapacity(dimIDs, 16*dims), "uint", dims) DllCall("Gdiplus\GdipImageGetFrameCount", "ptr", pBitmap, "ptr", &dimIDs, "uint*", frames:=0) + + ; For multiple frames, send WM_APP to WindowProc to render GIFs. if (frames > 1) { + ; Save frame delays inside GWLP_USERDATA because they are quite slow enough to impact timing. + DllCall("gdiplus\GdipGetPropertyItemSize", "ptr", pBitmap, "uint", 0x5100, "uint*", ItemSize:=0) ; PropertyTagFrameDelay + Item := DllCall("GlobalAlloc", "uint", 0, "uptr", ItemSize, "ptr") + DllCall("gdiplus\GdipGetPropertyItem", "ptr", pBitmap, "uint", 0x5100, "uint", ItemSize, "ptr", Item) + DllCall("SetWindowLongPtr", "ptr", hwnd, "int", GWLP_USERDATA := -21, "ptr", Item) + + ; Clone bitmap to avoid disposal, and initiate animation via PostMessage. DllCall("gdiplus\GdipCloneImage", "ptr", pBitmap, "ptr*", pBitmapClone:=0) DllCall("PostMessage", "ptr", hwnd, "uint", 0x8000, "uptr", -1, "ptr", pBitmapClone) } @@ -2233,35 +2242,67 @@ class ImagePut { ; WM_APP - Animate GIFs if (uMsg = 0x8000) { - ; Thanks Teadrinker - https://www.autohotkey.com/boards/viewtopic.php?f=76&t=83358 - - Critical ; Thread must never be interrupted. + Critical ; Thanks Teadrinker - https://www.autohotkey.com/boards/viewtopic.php?f=76&t=83358 pBitmap := lParam frame := wParam + 1 + Item := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", GWLP_USERDATA := -21, "ptr") ; If the window is destroyed, dispose the held bitmap. - if not DllCall("IsWindow", "ptr", hwnd) - return DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + if not DllCall("IsWindow", "ptr", hwnd) { + DllCall("GlobalFree", "ptr", Item) + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + return + } ; Get the next frame and delay. - DllCall("gdiplus\GdipGetPropertyItemSize", "ptr", pBitmap, "uint", 0x5100, "uint*", ItemSize:=0) ; PropertyTagFrameDelay - DllCall("gdiplus\GdipGetPropertyItem" , "ptr", pBitmap, "uint", 0x5100, "uint", ItemSize, "ptr", &Item := VarSetCapacity(Item, ItemSize)) - frames := NumGet(Item, 4, "uint") // 4 ; Max frames - delays := NumGet(Item, 8 + A_PtrSize, "ptr") ; Array of delays + frames := NumGet(Item+0, 4, "uint") // 4 ; Max frames + delays := NumGet(Item+0, 8 + A_PtrSize, "ptr") ; Array of delays frame := mod(frame, frames) ; Loop to first frame delay := Max(10 * NumGet(delays+0, frame*4, "uint"), 10) ; Minimum delay is 10ms ; Emulate behavior of setting 10 ms to 100 ms. (delay == 10) && delay := 100 ; See: https://www.biphelps.com/blog/The-Fastest-GIF-Does-Not-Exist + ; Randomize the delay in intervals of 15.6 + resolution := 15.6 + Random rand, 1, 100000 + percentage := mod(delay, resolution) / resolution + percentage *= 0.957 ; Higher is faster, lower is slower + + ; Randomized multiples of resolution + if ((rand := rand / 100000) > percentage) + res := Floor(delay / resolution) * resolution + else + res := Ceil(delay / resolution) * resolution + ; Async the next frame as soon as possible to prevent rendering lag. - pWndProc := RegisterCallback(ImagePut.WindowProc,,, &ImagePut) + static pWndProc := RegisterCallback(ImagePut.WindowProc,,, &ImagePut) next_frame := Func("DllCall").bind(pWndProc, "ptr", hwnd, "uint", uMsg, "uptr", frame, "ptr", pBitmap) - SetTimer % next_frame, % -1 * delay - + SetTimer % next_frame, % -1 * res + /* + ; Debug code + static start := 0, sum := 0, count := 0, sum2 := 0, count2 := 0 + DllCall("QueryPerformanceFrequency", "int64*", frequency:=0) + DllCall("QueryPerformanceCounter", "int64*", now:=0) + time := (now - start) / frequency * 1000 + if (time < 10000) { + sum += time + count++ + average := sum / count + sum2 += res + count2++ + Tooltip % "Current Tick:`t" Round(time, 4) + . "`nAverage FPS:`t" Round(average, 4) + . "`nQueued FPS:`t" Round(sum2 / count2, 4) + . "`nTarget FPS:`t" delay + . "`nPercentage:`t" percentage ", " rand + . "`nFloor and Ceiling:`t" Floor(delay / 15.6) * 15.6 ", " Ceil(delay / 15.6) * 15.6 + } + start := now + */ ; Select frame to show. - DllCall("Gdiplus\GdipImageGetFrameDimensionsCount", "ptr", pBitmap, "uint*", dims:=0) - DllCall("Gdiplus\GdipImageGetFrameDimensionsList", "ptr", pBitmap, "ptr", &dimIDs := VarSetCapacity(dimIDs, 16*dims), "uint", dims) + DllCall("gdiplus\GdipImageGetFrameDimensionsCount", "ptr", pBitmap, "uint*", dims:=0) + DllCall("gdiplus\GdipImageGetFrameDimensionsList", "ptr", pBitmap, "ptr", &dimIDs := VarSetCapacity(dimIDs, 16*dims), "uint", dims) DllCall("gdiplus\GdipImageSelectActiveFrame", "ptr", pBitmap, "ptr", &dimIDs, "uint", frame) ; Get Bitmap width and height. From ee7d82052c32cbbbf8c04da60d44da726b6c839d Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 15 Jun 2022 14:08:16 -0400 Subject: [PATCH 291/492] Accurate GIF animation delay --- ImagePut.ahk | 65 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 53 insertions(+), 12 deletions(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index 27ecafa2..792073d7 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2154,11 +2154,20 @@ class ImagePut { DllCall("DeleteObject", "ptr", hbm) DllCall("DeleteDC", "ptr", hdc) - ; For multiple frames, send WM_APP to WindowProc to render GIFs. + ; Check for multiple frames. DllCall("Gdiplus\GdipImageGetFrameDimensionsCount", "ptr", pBitmap, "uint*", &dims:=0) DllCall("Gdiplus\GdipImageGetFrameDimensionsList", "ptr", pBitmap, "ptr", dimIDs := Buffer(16*dims), "uint", dims) DllCall("Gdiplus\GdipImageGetFrameCount", "ptr", pBitmap, "ptr", dimIDs, "uint*", &frames:=0) + + ; For multiple frames, send WM_APP to WindowProc to render GIFs. if (frames > 1) { + ; Save frame delays inside GWLP_USERDATA because they are quite slow enough to impact timing. + DllCall("gdiplus\GdipGetPropertyItemSize", "ptr", pBitmap, "uint", 0x5100, "uint*", &ItemSize:=0) ; PropertyTagFrameDelay + Item := DllCall("GlobalAlloc", "uint", 0, "uptr", ItemSize, "ptr") + DllCall("gdiplus\GdipGetPropertyItem", "ptr", pBitmap, "uint", 0x5100, "uint", ItemSize, "ptr", Item) + DllCall("SetWindowLongPtr", "ptr", hwnd, "int", GWLP_USERDATA := -21, "ptr", Item) + + ; Clone bitmap to avoid disposal, and initiate animation via PostMessage. DllCall("gdiplus\GdipCloneImage", "ptr", pBitmap, "ptr*", &pBitmapClone:=0) DllCall("PostMessage", "ptr", hwnd, "uint", 0x8000, "uptr", -1, "ptr", pBitmapClone) } @@ -2234,19 +2243,19 @@ class ImagePut { ; WM_APP - Animate GIFs if (uMsg = 0x8000) { - ; Thanks Teadrinker - https://www.autohotkey.com/boards/viewtopic.php?f=76&t=83358 - - Critical ; Thread must never be interrupted. + Critical ; Thanks Teadrinker - https://www.autohotkey.com/boards/viewtopic.php?f=76&t=83358 pBitmap := lParam frame := wParam + 1 + Item := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", GWLP_USERDATA := -21, "ptr") ; If the window is destroyed, dispose the held bitmap. - if not DllCall("IsWindow", "ptr", hwnd) - return DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + if not DllCall("IsWindow", "ptr", hwnd) { + DllCall("GlobalFree", "ptr", Item) + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + return + } ; Get the next frame and delay. - DllCall("gdiplus\GdipGetPropertyItemSize", "ptr", pBitmap, "uint", 0x5100, "uint*", &ItemSize:=0) ; PropertyTagFrameDelay - DllCall("gdiplus\GdipGetPropertyItem" , "ptr", pBitmap, "uint", 0x5100, "uint", ItemSize, "ptr", Item := Buffer(ItemSize)) frames := NumGet(Item, 4, "uint") // 4 ; Max frames delays := NumGet(Item, 8 + A_PtrSize, "ptr") ; Array of delays frame := mod(frame, frames) ; Loop to first frame @@ -2255,11 +2264,43 @@ class ImagePut { ; Emulate behavior of setting 10 ms to 100 ms. (delay == 10) && delay := 100 ; See: https://www.biphelps.com/blog/The-Fastest-GIF-Does-Not-Exist - ; Async the next frame as soon as possible to prevent rendering lag. - SetTimer WindowProc.bind(hwnd, uMsg, frame, pBitmap), -1 * delay - + ; Randomize the delay in intervals of 15.6 + resolution := 15.6 + rand := random() + percentage := mod(delay, resolution) / resolution + percentage *= 0.957 ; Higher is faster, lower is slower + ; Randomized multiples of resolution + if (rand > percentage) + res := Floor(delay / resolution) * resolution + else + res := Ceil(delay / resolution) * resolution + ; Async the next frame as soon as possible to prevent rendering lag. + SetTimer WindowProc.bind(hwnd, uMsg, frame, pBitmap), -1 * res + + + /* + ; Debug code + static start := 0, sum := 0, count := 0, sum2 := 0, count2 := 0 + DllCall("QueryPerformanceFrequency", "int64*", &frequency:=0) + DllCall("QueryPerformanceCounter", "int64*", &now:=0) + time := (now - start) / frequency * 1000 + if (time < 10000) { + sum += time + count++ + average := sum / count + sum2 += res + count2++ + Tooltip "Current Tick:`t" Round(time, 4) + . "`nAverage FPS:`t" Round(average, 4) + . "`nQueued FPS:`t" Round(sum2 / count2, 4) + . "`nTarget FPS:`t" delay + . "`nPercentage:`t" percentage ", " rand + . "`nFloor and Ceiling:`t" Floor(delay / 15.6) * 15.6 ", " Ceil(delay / 15.6) * 15.6 + } + start := now + */ ; Select frame to show. DllCall("gdiplus\GdipImageGetFrameDimensionsCount", "ptr", pBitmap, "uint*", &dims:=0) DllCall("gdiplus\GdipImageGetFrameDimensionsList", "ptr", pBitmap, "ptr", dimIDs := Buffer(16*dims), "uint", dims) @@ -2880,7 +2921,7 @@ class ImagePut { ; Create a filepath based on the timestamp. if (filename == "") { - filename := FormatTime(, "yyyy-MM-dd HH?mm?ss") + filename := FormatTime(, "yyyy-MM-dd HH꞉mm꞉ss") filepath := directory "\" filename "." extension while FileExist(filepath) filepath := directory "\" filename " (" A_Index ")." extension From 580bade820e5e08c7ac2b59d83a30276f253054c Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 16 Jun 2022 00:45:04 -0400 Subject: [PATCH 292/492] redundant return --- ImagePut.ahk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index 792073d7..9a661a38 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2220,11 +2220,11 @@ class ImagePut { ; WM_CREATE if (uMsg = 0x1) - return Persistent(++active_windows) + Persistent(++active_windows) ; WM_DESTROY if (uMsg = 0x2) - return Persistent(--active_windows) + Persistent(--active_windows) ; WM_LBUTTONDOWN if (uMsg = 0x201) { From 17cf3efbac25bc53ee024888f6ebede65465f0d5 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 16 Jun 2022 00:51:54 -0400 Subject: [PATCH 293/492] Window Procedures should return --- ImagePut (for v1).ahk | 1 + ImagePut.ahk | 1 + 2 files changed, 2 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 33fb43d4..d1361b5c 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2327,6 +2327,7 @@ class ImagePut { hbm := DllCall("SelectObject", "ptr", hdc, "ptr", obm, "ptr") DllCall("DeleteObject", "ptr", hbm) DllCall("DeleteDC", "ptr", hdc) + return } ; Must return diff --git a/ImagePut.ahk b/ImagePut.ahk index 9a661a38..5d46d189 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2328,6 +2328,7 @@ class ImagePut { hbm := DllCall("SelectObject", "ptr", hdc, "ptr", obm, "ptr") DllCall("DeleteObject", "ptr", hbm) DllCall("DeleteDC", "ptr", hdc) + return } ; Must return From 8fd8e9cb3d341edd0f3562e5881c78477a320c9c Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 16 Jun 2022 01:55:24 -0400 Subject: [PATCH 294/492] Refactor gdiplus boilerplate --- ImagePut (for v1).ahk | 62 ++++++++++++++++++++++++------------------- ImagePut.ahk | 62 ++++++++++++++++++++++++------------------- 2 files changed, 70 insertions(+), 54 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index d1361b5c..288ad495 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2938,51 +2938,59 @@ class ImagePut { else filepath := directory "\" filename "." extension } - ; All references to gdiplus and pToken must be absolute! - static gdiplus := 0, pToken := 0 - gdiplusStartup() { - ImagePut.gdiplus++ + return this.gdiplus(1) + } + + gdiplusShutdown(cotype := "") { + return this.gdiplus(-1, cotype) + } + + gdiplus(vary := 0, cotype := "") { + static pToken := 0 ; Takes advantage of the fact that objects contain identical methods. + static instances := 0 ; And therefore static variables can share data across instances. ; Startup gdiplus when counter rises from 0 -> 1. - if (ImagePut.gdiplus == 1) { + if (instances = 0 && vary = 1) { DllCall("LoadLibrary", "str", "gdiplus") VarSetCapacity(si, A_PtrSize = 4 ? 16:24, 0) ; sizeof(GdiplusStartupInput) = 16, 24 NumPut(0x1, si, "uint") DllCall("gdiplus\GdiplusStartup", "ptr*", pToken:=0, "ptr", &si, "ptr", 0) - ImagePut.pToken := pToken } - } - - gdiplusShutdown(cotype := "") { - ImagePut.gdiplus-- - - ; Check for unpaired calls of gdiplusShutdown. - if (ImagePut.gdiplus < 0) - throw Exception("Missing ImagePut.gdiplusStartup().") ; Shutdown gdiplus when counter falls from 1 -> 0. - if (ImagePut.gdiplus == 0) { - pToken := ImagePut.pToken + if (instances = 1 && vary = -1) { DllCall("gdiplus\GdiplusShutdown", "ptr", pToken) DllCall("FreeLibrary", "ptr", DllCall("GetModuleHandle", "str", "gdiplus", "ptr")) - ; Exit if GDI+ is still loaded. GdiplusNotInitialized = 18 - if (18 != DllCall("gdiplus\GdipCreateImageAttributes", "ptr*", ImageAttr:=0)) { - DllCall("gdiplus\GdipDisposeImageAttributes", "ptr", ImageAttr) - return - } - ; Otherwise GDI+ has been truly unloaded from the script and objects are out of scope. - if (cotype = "bitmap") - throw Exception("Bitmap is out of scope. `n`nIf you wish to handle raw pointers to GDI+ bitmaps, add the line" - . "`n`n`t`t" this.__class ".gdiplusStartup()`n`nor 'pToken := Gdip_Startup()' to the top of your script." - . "`nAlternatively, use 'pic := ImagePutBuffer()' with 'pic.pBitmap'." - . "`nYou can copy this message by pressing Ctrl + C.", -4) + if (cotype = "bitmap") { + + ; Check if GDI+ is still loaded. GdiplusNotInitialized = 18 + assert := (18 != DllCall("gdiplus\GdipCreateImageAttributes", "ptr*", ImageAttr:=0)) + DllCall("gdiplus\GdipDisposeImageAttributes", "ptr", ImageAttr) + + if not assert + throw Exception("Bitmap is out of scope. `n`nIf you wish to handle raw pointers to GDI+ bitmaps, add the line" + . "`n`n`t`t" this.__class ".gdiplusStartup()" + . "`n`nto the top of your script. If using Gdip_All.ahk use pToken := Gdip_Startup()." + . "`nAlternatively, use pic := ImagePutBuffer() and pic.pBitmap instead." + . "`nYou can copy this message by pressing Ctrl + C.", -5) + } } + + ; Increment or decrement the number of available instances. + instances += vary + + ; Check for unpaired calls of gdiplusShutdown. + if (instances < 0) + throw Exception("Missing gdiplusStartup().") + + ; When vary is 0, just return the number of active instances! + return instances } ; Get the image width and height. diff --git a/ImagePut.ahk b/ImagePut.ahk index 5d46d189..1b56815d 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2939,51 +2939,59 @@ class ImagePut { else filepath := directory "\" filename "." extension } - ; All references to gdiplus and pToken must be absolute! - static gdiplus := 0, pToken := 0 - static gdiplusStartup() { - ImagePut.gdiplus++ + return this.gdiplus(1) + } + + static gdiplusShutdown(cotype := "") { + return this.gdiplus(-1, cotype) + } + + static gdiplus(vary := 0, cotype := "") { + static pToken := 0 ; Takes advantage of the fact that objects contain identical methods. + static instances := 0 ; And therefore static variables can share data across instances. ; Startup gdiplus when counter rises from 0 -> 1. - if (ImagePut.gdiplus == 1) { + if (instances = 0 && vary = 1) { DllCall("LoadLibrary", "str", "gdiplus") si := Buffer(A_PtrSize = 4 ? 16:24, 0) ; sizeof(GdiplusStartupInput) = 16, 24 NumPut("uint", 0x1, si) DllCall("gdiplus\GdiplusStartup", "ptr*", &pToken:=0, "ptr", si, "ptr", 0) - ImagePut.pToken := pToken } - } - - static gdiplusShutdown(cotype := "") { - ImagePut.gdiplus-- - - ; Check for unpaired calls of gdiplusShutdown. - if (ImagePut.gdiplus < 0) - throw Error("Missing ImagePut.gdiplusStartup().") ; Shutdown gdiplus when counter falls from 1 -> 0. - if (ImagePut.gdiplus == 0) { - pToken := ImagePut.pToken + if (instances = 1 && vary = -1) { DllCall("gdiplus\GdiplusShutdown", "ptr", pToken) DllCall("FreeLibrary", "ptr", DllCall("GetModuleHandle", "str", "gdiplus", "ptr")) - ; Exit if GDI+ is still loaded. GdiplusNotInitialized = 18 - if (18 != DllCall("gdiplus\GdipCreateImageAttributes", "ptr*", &ImageAttr:=0)) { - DllCall("gdiplus\GdipDisposeImageAttributes", "ptr", ImageAttr) - return - } - ; Otherwise GDI+ has been truly unloaded from the script and objects are out of scope. - if (cotype = "bitmap") - throw Error("Bitmap is out of scope. `n`nIf you wish to handle raw pointers to GDI+ bitmaps, add the line" - . "`n`n`t`t" this.prototype.__class ".gdiplusStartup()`n`nor 'pToken := Gdip_Startup()' to the top of your script." - . "`nAlternatively, use 'pic := ImagePutBuffer()' with 'pic.pBitmap'." - . "`nYou can copy this message by pressing Ctrl + C.", -3) + if (cotype = "bitmap") { + + ; Check if GDI+ is still loaded. GdiplusNotInitialized = 18 + assert := (18 != DllCall("gdiplus\GdipCreateImageAttributes", "ptr*", &ImageAttr:=0)) + DllCall("gdiplus\GdipDisposeImageAttributes", "ptr", ImageAttr) + + if not assert + throw Error("Bitmap is out of scope. `n`nIf you wish to handle raw pointers to GDI+ bitmaps, add the line" + . "`n`n`t`t" this.prototype.__class ".gdiplusStartup()" + . "`n`nto the top of your script. If using Gdip_All.ahk use pToken := Gdip_Startup()." + . "`nAlternatively, use pic := ImagePutBuffer() and pic.pBitmap instead." + . "`nYou can copy this message by pressing Ctrl + C.", -4) + } } + + ; Increment or decrement the number of available instances. + instances += vary + + ; Check for unpaired calls of gdiplusShutdown. + if (instances < 0) + throw Error("Missing gdiplusStartup().") + + ; When vary is 0, just return the number of active instances! + return instances } ; Get the image width and height. From 7f11a8c87ae83ffb04ab4e38bae1b49c10429a15 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 16 Jun 2022 14:43:58 -0400 Subject: [PATCH 295/492] GIF animations need GDI+ scope --- ImagePut (for v1).ahk | 4 ++++ ImagePut.ahk | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 288ad495..09f40e7a 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2169,6 +2169,9 @@ class ImagePut { ; Clone bitmap to avoid disposal, and initiate animation via PostMessage. DllCall("gdiplus\GdipCloneImage", "ptr", pBitmap, "ptr*", pBitmapClone:=0) DllCall("PostMessage", "ptr", hwnd, "uint", 0x8000, "uptr", -1, "ptr", pBitmapClone) + + ; Preserve GDI+ scope. + ImagePut.gdiplusStartup() } return hwnd @@ -2251,6 +2254,7 @@ class ImagePut { if not DllCall("IsWindow", "ptr", hwnd) { DllCall("GlobalFree", "ptr", Item) DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + ImagePut.gdiplusShutdown() return } diff --git a/ImagePut.ahk b/ImagePut.ahk index 1b56815d..3a395bcf 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2170,6 +2170,9 @@ class ImagePut { ; Clone bitmap to avoid disposal, and initiate animation via PostMessage. DllCall("gdiplus\GdipCloneImage", "ptr", pBitmap, "ptr*", &pBitmapClone:=0) DllCall("PostMessage", "ptr", hwnd, "uint", 0x8000, "uptr", -1, "ptr", pBitmapClone) + + ; Preserve GDI+ scope. + ImagePut.gdiplusStartup() } return hwnd @@ -2252,6 +2255,7 @@ class ImagePut { if not DllCall("IsWindow", "ptr", hwnd) { DllCall("GlobalFree", "ptr", Item) DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + ImagePut.gdiplusShutdown() return } From a6b7ee8c9c3ff71da101798a67bd76f26a09e3cf Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 16 Jun 2022 14:46:47 -0400 Subject: [PATCH 296/492] Add drag and drop functionality to open all images --- ImagePut (for v1).ahk | 16 +++++++++++++++- ImagePut.ahk | 16 +++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 09f40e7a..d28ca3ce 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -3231,4 +3231,18 @@ class ImageEqual extends ImagePut { ; Compare stopped byte. return (byte == size) ? True : False } -} ; End of ImageEqual class. \ No newline at end of file +} ; End of ImageEqual class. + + +; Drag and drop files directly onto this script file. +if (A_LineFile == A_ScriptFullPath) { + filepath := "" + for each, arg in A_Args { + filepath .= arg . A_Space + if FileExist(Trim(filepath)) { + SplitPath % filepath, filename + ImagePutWindow({file: filepath}, filename) + filepath := "" + } + } +} \ No newline at end of file diff --git a/ImagePut.ahk b/ImagePut.ahk index 3a395bcf..80c91acf 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -3232,4 +3232,18 @@ class ImageEqual extends ImagePut { ; Compare stopped byte. return (byte == size) ? True : False } -} ; End of ImageEqual class. \ No newline at end of file +} ; End of ImageEqual class. + + +; Drag and drop files directly onto this script file. +if (A_LineFile == A_ScriptFullPath) { + filepath := "" + for each, arg in A_Args { + filepath .= arg . A_Space + if FileExist(Trim(filepath)) { + SplitPath filepath, &filename + ImagePutWindow({file: filepath}, filename) + filepath := "" + } + } +} \ No newline at end of file From 8cf6e34270720bcbb38e91668d29ef160cbd5803 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 16 Jun 2022 16:03:33 -0400 Subject: [PATCH 297/492] Load GIF clone to memory immediately --- ImagePut (for v1).ahk | 7 ++++--- ImagePut.ahk | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index d28ca3ce..e7f7a8f2 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2154,9 +2154,9 @@ class ImagePut { DllCall("DeleteDC", "ptr", hdc) ; Check for multiple frames. - DllCall("Gdiplus\GdipImageGetFrameDimensionsCount", "ptr", pBitmap, "uint*", dims:=0) - DllCall("Gdiplus\GdipImageGetFrameDimensionsList", "ptr", pBitmap, "ptr", &dimIDs := VarSetCapacity(dimIDs, 16*dims), "uint", dims) - DllCall("Gdiplus\GdipImageGetFrameCount", "ptr", pBitmap, "ptr", &dimIDs, "uint*", frames:=0) + DllCall("gdiplus\GdipImageGetFrameDimensionsCount", "ptr", pBitmap, "uint*", dims:=0) + DllCall("gdiplus\GdipImageGetFrameDimensionsList", "ptr", pBitmap, "ptr", &dimIDs := VarSetCapacity(dimIDs, 16*dims), "uint", dims) + DllCall("gdiplus\GdipImageGetFrameCount", "ptr", pBitmap, "ptr", &dimIDs, "uint*", frames:=0) ; For multiple frames, send WM_APP to WindowProc to render GIFs. if (frames > 1) { @@ -2168,6 +2168,7 @@ class ImagePut { ; Clone bitmap to avoid disposal, and initiate animation via PostMessage. DllCall("gdiplus\GdipCloneImage", "ptr", pBitmap, "ptr*", pBitmapClone:=0) + DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmap) DllCall("PostMessage", "ptr", hwnd, "uint", 0x8000, "uptr", -1, "ptr", pBitmapClone) ; Preserve GDI+ scope. diff --git a/ImagePut.ahk b/ImagePut.ahk index 80c91acf..e1c974f3 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2155,9 +2155,9 @@ class ImagePut { DllCall("DeleteDC", "ptr", hdc) ; Check for multiple frames. - DllCall("Gdiplus\GdipImageGetFrameDimensionsCount", "ptr", pBitmap, "uint*", &dims:=0) - DllCall("Gdiplus\GdipImageGetFrameDimensionsList", "ptr", pBitmap, "ptr", dimIDs := Buffer(16*dims), "uint", dims) - DllCall("Gdiplus\GdipImageGetFrameCount", "ptr", pBitmap, "ptr", dimIDs, "uint*", &frames:=0) + DllCall("gdiplus\GdipImageGetFrameDimensionsCount", "ptr", pBitmap, "uint*", &dims:=0) + DllCall("gdiplus\GdipImageGetFrameDimensionsList", "ptr", pBitmap, "ptr", dimIDs := Buffer(16*dims), "uint", dims) + DllCall("gdiplus\GdipImageGetFrameCount", "ptr", pBitmap, "ptr", dimIDs, "uint*", &frames:=0) ; For multiple frames, send WM_APP to WindowProc to render GIFs. if (frames > 1) { @@ -2169,6 +2169,7 @@ class ImagePut { ; Clone bitmap to avoid disposal, and initiate animation via PostMessage. DllCall("gdiplus\GdipCloneImage", "ptr", pBitmap, "ptr*", &pBitmapClone:=0) + DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmap) DllCall("PostMessage", "ptr", hwnd, "uint", 0x8000, "uptr", -1, "ptr", pBitmapClone) ; Preserve GDI+ scope. From 42bc2016ec901ebd62f8369586755be3b8558403 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 16 Jun 2022 17:38:47 -0400 Subject: [PATCH 298/492] Fix memory leak when displaying GIFs --- ImagePut (for v1).ahk | 30 ++++++++++++++++-------------- ImagePut.ahk | 30 ++++++++++++++++-------------- 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index e7f7a8f2..8b8cb3aa 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2164,12 +2164,12 @@ class ImagePut { DllCall("gdiplus\GdipGetPropertyItemSize", "ptr", pBitmap, "uint", 0x5100, "uint*", ItemSize:=0) ; PropertyTagFrameDelay Item := DllCall("GlobalAlloc", "uint", 0, "uptr", ItemSize, "ptr") DllCall("gdiplus\GdipGetPropertyItem", "ptr", pBitmap, "uint", 0x5100, "uint", ItemSize, "ptr", Item) - DllCall("SetWindowLongPtr", "ptr", hwnd, "int", GWLP_USERDATA := -21, "ptr", Item) ; Clone bitmap to avoid disposal, and initiate animation via PostMessage. DllCall("gdiplus\GdipCloneImage", "ptr", pBitmap, "ptr*", pBitmapClone:=0) - DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmap) - DllCall("PostMessage", "ptr", hwnd, "uint", 0x8000, "uptr", -1, "ptr", pBitmapClone) + DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmapClone) + DllCall("SetWindowLongPtr", "ptr", hwnd, "int", GWLP_USERDATA := -21, "ptr", pBitmapClone) + DllCall("PostMessage", "ptr", hwnd, "uint", 0x8000, "uptr", -1, "ptr", Item) ; Preserve GDI+ scope. ImagePut.gdiplusStartup() @@ -2226,8 +2226,14 @@ class ImagePut { Hotkey % "^+F12", % void, On ; WM_DESTROY - if (uMsg = 0x2) + if (uMsg = 0x2) { + if pBitmap := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", GWLP_USERDATA := -21, "ptr") { + DllCall("SetWindowLongPtr", "ptr", hwnd, "int", GWLP_USERDATA := -21, "ptr", 0) + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + IsObject(ImagePut) && ImagePut.gdiplusShutdown() + } Hotkey % "^+F12", % void, Off ; Cannot disable, does nothing + } ; WM_LBUTTONDOWN if (uMsg = 0x201) { @@ -2247,17 +2253,13 @@ class ImagePut { ; WM_APP - Animate GIFs if (uMsg = 0x8000) { Critical ; Thanks Teadrinker - https://www.autohotkey.com/boards/viewtopic.php?f=76&t=83358 - pBitmap := lParam + frame := wParam + 1 - Item := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", GWLP_USERDATA := -21, "ptr") + Item := lParam - ; If the window is destroyed, dispose the held bitmap. - if not DllCall("IsWindow", "ptr", hwnd) { - DllCall("GlobalFree", "ptr", Item) - DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) - ImagePut.gdiplusShutdown() - return - } + ; If the window is destroyed... + if !(pBitmap := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", GWLP_USERDATA := -21, "ptr")) + return DllCall("GlobalFree", "ptr", Item) ; Sometimes works. ; Get the next frame and delay. frames := NumGet(Item+0, 4, "uint") // 4 ; Max frames @@ -2282,7 +2284,7 @@ class ImagePut { ; Async the next frame as soon as possible to prevent rendering lag. static pWndProc := RegisterCallback(ImagePut.WindowProc,,, &ImagePut) - next_frame := Func("DllCall").bind(pWndProc, "ptr", hwnd, "uint", uMsg, "uptr", frame, "ptr", pBitmap) + next_frame := Func("DllCall").bind(pWndProc, "ptr", hwnd, "uint", uMsg, "uptr", frame, "ptr", Item) SetTimer % next_frame, % -1 * res /* ; Debug code diff --git a/ImagePut.ahk b/ImagePut.ahk index e1c974f3..07e61282 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2165,12 +2165,12 @@ class ImagePut { DllCall("gdiplus\GdipGetPropertyItemSize", "ptr", pBitmap, "uint", 0x5100, "uint*", &ItemSize:=0) ; PropertyTagFrameDelay Item := DllCall("GlobalAlloc", "uint", 0, "uptr", ItemSize, "ptr") DllCall("gdiplus\GdipGetPropertyItem", "ptr", pBitmap, "uint", 0x5100, "uint", ItemSize, "ptr", Item) - DllCall("SetWindowLongPtr", "ptr", hwnd, "int", GWLP_USERDATA := -21, "ptr", Item) ; Clone bitmap to avoid disposal, and initiate animation via PostMessage. DllCall("gdiplus\GdipCloneImage", "ptr", pBitmap, "ptr*", &pBitmapClone:=0) - DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmap) - DllCall("PostMessage", "ptr", hwnd, "uint", 0x8000, "uptr", -1, "ptr", pBitmapClone) + DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmapClone) + DllCall("SetWindowLongPtr", "ptr", hwnd, "int", GWLP_USERDATA := -21, "ptr", pBitmapClone) + DllCall("PostMessage", "ptr", hwnd, "uint", 0x8000, "uptr", -1, "ptr", Item) ; Preserve GDI+ scope. ImagePut.gdiplusStartup() @@ -2227,8 +2227,14 @@ class ImagePut { Persistent(++active_windows) ; WM_DESTROY - if (uMsg = 0x2) + if (uMsg = 0x2) { + if pBitmap := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", GWLP_USERDATA := -21, "ptr") { + DllCall("SetWindowLongPtr", "ptr", hwnd, "int", GWLP_USERDATA := -21, "ptr", 0) + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + IsObject(ImagePut) && ImagePut.gdiplusShutdown() + } Persistent(--active_windows) + } ; WM_LBUTTONDOWN if (uMsg = 0x201) { @@ -2248,17 +2254,13 @@ class ImagePut { ; WM_APP - Animate GIFs if (uMsg = 0x8000) { Critical ; Thanks Teadrinker - https://www.autohotkey.com/boards/viewtopic.php?f=76&t=83358 - pBitmap := lParam + frame := wParam + 1 - Item := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", GWLP_USERDATA := -21, "ptr") + Item := lParam - ; If the window is destroyed, dispose the held bitmap. - if not DllCall("IsWindow", "ptr", hwnd) { - DllCall("GlobalFree", "ptr", Item) - DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) - ImagePut.gdiplusShutdown() - return - } + ; If the window is destroyed... + if !(pBitmap := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", GWLP_USERDATA := -21, "ptr")) + return DllCall("GlobalFree", "ptr", Item) ; Sometimes works. ; Get the next frame and delay. frames := NumGet(Item, 4, "uint") // 4 ; Max frames @@ -2282,7 +2284,7 @@ class ImagePut { res := Ceil(delay / resolution) * resolution ; Async the next frame as soon as possible to prevent rendering lag. - SetTimer WindowProc.bind(hwnd, uMsg, frame, pBitmap), -1 * res + SetTimer WindowProc.bind(hwnd, uMsg, frame, Item), -1 * res /* From 5bb5b2d1c851def7e2023a80aa492e81da3f5fa0 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 16 Jun 2022 20:10:48 -0400 Subject: [PATCH 299/492] ImageShow is cooler for animated GIFs --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 8b8cb3aa..0f48f70b 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -3244,7 +3244,7 @@ if (A_LineFile == A_ScriptFullPath) { filepath .= arg . A_Space if FileExist(Trim(filepath)) { SplitPath % filepath, filename - ImagePutWindow({file: filepath}, filename) + ImageShow({file: filepath}, filename) filepath := "" } } diff --git a/ImagePut.ahk b/ImagePut.ahk index 07e61282..e542434b 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -3245,7 +3245,7 @@ if (A_LineFile == A_ScriptFullPath) { filepath .= arg . A_Space if FileExist(Trim(filepath)) { SplitPath filepath, &filename - ImagePutWindow({file: filepath}, filename) + ImageShow({file: filepath}, filename) filepath := "" } } From e8483487473476c0a85c507b4a90489c7f2fbc35 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 17 Jun 2022 17:53:06 -0400 Subject: [PATCH 300/492] update demo --- demo.ahk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/demo.ahk b/demo.ahk index 936f04d5..6a99987d 100644 --- a/demo.ahk +++ b/demo.ahk @@ -2,11 +2,11 @@ #include *i ImagePut (for v%true%).ahk #singleinstance force -; This script runs on both AutoHotkey v1 and v2. +; This script runs on both AutoHotkey v1 and v2. hwnd := ImagePutWindow("https://picsum.photos/500", "Thank you for trying ImagePut ?") ; Save the image as a file. ImagePutFile(hwnd) ; Copy the window handle to the clipboard. -ImagePutClipboard(hwnd) +ImagePutClipboard(hwnd) \ No newline at end of file From bd5c8a3afedf7f3757dbbab9f033858365ef2dba Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 17 Jun 2022 18:07:58 -0400 Subject: [PATCH 301/492] cute demo --- demo.ahk | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/demo.ahk b/demo.ahk index 6a99987d..75d0b57a 100644 --- a/demo.ahk +++ b/demo.ahk @@ -2,11 +2,11 @@ #include *i ImagePut (for v%true%).ahk #singleinstance force -; This script runs on both AutoHotkey v1 and v2. -hwnd := ImagePutWindow("https://picsum.photos/500", "Thank you for trying ImagePut ?") +; Show image in window. +hwnd := ImagePutWindow("https://picsum.photos/1000/200", "Thank you for trying ImagePut ?") -; Save the image as a file. -ImagePutFile(hwnd) +; Save image to file. +filepath := ImagePutFile("https://i.imgur.com/cCyb8bq.gif") -; Copy the window handle to the clipboard. -ImagePutClipboard(hwnd) \ No newline at end of file +; Display images without borders. Right click image to close. +ImageShow(filepath) \ No newline at end of file From 0035ad3094bcdb4d870319a75e178306cd2e1d21 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 17 Jun 2022 18:08:13 -0400 Subject: [PATCH 302/492] v1.8.1 --- ImagePut (for v1).ahk | 4 ++-- ImagePut.ahk | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 0f48f70b..bdbf01b7 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2,8 +2,8 @@ ; License: MIT License ; Author: Edison Hua (iseahound) ; Github: https://github.com/iseahound/ImagePut -; Date: 2022-06-14 -; Version: 1.8.0 +; Date: 2022-06-17 +; Version: 1.8.1 #Requires AutoHotkey v1.1.33+ diff --git a/ImagePut.ahk b/ImagePut.ahk index e542434b..33b16fbf 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2,8 +2,8 @@ ; License: MIT License ; Author: Edison Hua (iseahound) ; Github: https://github.com/iseahound/ImagePut -; Date: 2022-06-14 -; Version: 1.8.0 +; Date: 2022-06-17 +; Version: 1.8.1 #Requires AutoHotkey v2.0-beta.3+ From d98e451f6dfc16f8dfdf222441eab128bfca2c54 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 18 Jun 2022 21:04:36 -0400 Subject: [PATCH 303/492] Validate A_Args length --- ImagePut (for v1).ahk | 4 ++-- ImagePut.ahk | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index bdbf01b7..0489afca 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2303,7 +2303,7 @@ class ImagePut { . "`nQueued FPS:`t" Round(sum2 / count2, 4) . "`nTarget FPS:`t" delay . "`nPercentage:`t" percentage ", " rand - . "`nFloor and Ceiling:`t" Floor(delay / 15.6) * 15.6 ", " Ceil(delay / 15.6) * 15.6 + . "`nFloor and Ceiling:`t" Floor(delay / resolution) * resolution ", " Ceil(delay / resolution) * resolution } start := now */ @@ -3238,7 +3238,7 @@ class ImageEqual extends ImagePut { ; Drag and drop files directly onto this script file. -if (A_LineFile == A_ScriptFullPath) { +if (A_Args.length() > 0 and A_LineFile == A_ScriptFullPath) { filepath := "" for each, arg in A_Args { filepath .= arg . A_Space diff --git a/ImagePut.ahk b/ImagePut.ahk index 33b16fbf..b8de7e8f 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2304,7 +2304,7 @@ class ImagePut { . "`nQueued FPS:`t" Round(sum2 / count2, 4) . "`nTarget FPS:`t" delay . "`nPercentage:`t" percentage ", " rand - . "`nFloor and Ceiling:`t" Floor(delay / 15.6) * 15.6 ", " Ceil(delay / 15.6) * 15.6 + . "`nFloor and Ceiling:`t" Floor(delay / resolution) * resolution ", " Ceil(delay / resolution) * resolution } start := now */ @@ -3239,7 +3239,7 @@ class ImageEqual extends ImagePut { ; Drag and drop files directly onto this script file. -if (A_LineFile == A_ScriptFullPath) { +if (A_Args.length > 0 and A_LineFile == A_ScriptFullPath) { filepath := "" for each, arg in A_Args { filepath .= arg . A_Space From f7fa88fbf4d070ceb4866daa7c61b24fd50cc88f Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 18 Jun 2022 21:33:53 -0400 Subject: [PATCH 304/492] Shorten URLs --- ImagePut (for v1).ahk | 10 +++++----- ImagePut.ahk | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 0489afca..5bd7edf4 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1480,7 +1480,7 @@ class ImagePut { } from_wicBitmap(image) { - ; IWICBitmapSource::GetSize - https://github.com/tpn/winsdk-10/blob/9b69fd26ac0c7d0b83d378dba01080e93349c2ed/Include/10.0.16299.0/um/wincodec.h#L1304 + ; IWICBitmapSource::GetSize - https://github.com/iseahound/winsdk-10/blob/master/Include/10.0.16299.0/um/wincodec.h#L1304 DllCall(NumGet(NumGet(image + 0) + A_PtrSize*3), "ptr", image, "uint*", width:=0, "uint*", height:=0) ; Intialize an empty pBitmap using managed memory. @@ -1501,7 +1501,7 @@ class ImagePut { Scan0 := NumGet(BitmapData, 16, "ptr") stride := NumGet(BitmapData, 8, "int") - ; IWICBitmapSource::CopyPixels - https://github.com/tpn/winsdk-10/blob/9b69fd26ac0c7d0b83d378dba01080e93349c2ed/Include/10.0.16299.0/um/wincodec.h#L1322 + ; IWICBitmapSource::CopyPixels - https://github.com/iseahound/winsdk-10/blob/master/Include/10.0.16299.0/um/wincodec.h#L1322 DllCall(NumGet(NumGet(image + 0) + A_PtrSize*7), "ptr", image, "ptr", &Rect, "uint", stride, "uint", stride * height, "ptr", Scan0) ; Write pixels to bitmap. @@ -2788,7 +2788,7 @@ class ImagePut { IWICImagingFactory := ComObjCreate(CLSID_WICImagingFactory := "{CACAF262-9370-4615-A13B-9F5539DA4C0A}", IID_IWICImagingFactory := "{EC5EC8A9-C395-4314-9C77-54D7A935FF70}") ; WICBitmapNoCache must be 1! - ; IWICImagingFactory::CreateBitmap - https://github.com/tpn/winsdk-10/blob/9b69fd26ac0c7d0b83d378dba01080e93349c2ed/Include/10.0.16299.0/um/wincodec.h#L6447 + ; IWICImagingFactory::CreateBitmap - https://github.com/iseahound/winsdk-10/blob/master/Include/10.0.16299.0/um/wincodec.h#L6447 DllCall("ole32\CLSIDFromString", "wstr", GUID_WICPixelFormat32bppBGRA := "{6fddc324-4e03-4bfe-b185-3d77768dc90f}", "ptr", &CLSID := VarSetCapacity(CLSID, 16), "uint") DllCall(NumGet(NumGet(IWICImagingFactory + 0) + A_PtrSize*17), "ptr", IWICImagingFactory, "uint", width, "uint", height, "ptr", &CLSID, "int", 1, "ptr*", wicBitmap:=0) @@ -2796,10 +2796,10 @@ class ImagePut { NumPut( width, Rect, 8, "uint") ; Width NumPut( height, Rect, 12, "uint") ; Height - ; IWICBitmap::Lock - https://github.com/tpn/winsdk-10/blob/9b69fd26ac0c7d0b83d378dba01080e93349c2ed/Include/10.0.16299.0/um/wincodec.h#L2232 + ; IWICBitmap::Lock - https://github.com/iseahound/winsdk-10/blob/master/Include/10.0.16299.0/um/wincodec.h#L2232 DllCall(NumGet(NumGet(wicBitmap + 0) + A_PtrSize*8), "Ptr", wicBitmap, "Ptr", &Rect, "uint", 0x1, "ptr*", Lock:=0) - ; IWICBitmapLock::GetDataPointer - https://github.com/tpn/winsdk-10/blob/9b69fd26ac0c7d0b83d378dba01080e93349c2ed/Include/10.0.16299.0/um/wincodec.h#L2104 + ; IWICBitmapLock::GetDataPointer - https://github.com/iseahound/winsdk-10/blob/master/Include/10.0.16299.0/um/wincodec.h#L2104 DllCall(NumGet(NumGet(Lock + 0) + A_PtrSize*5), "Ptr", Lock, "uint*", size:=0, "ptr*", Scan0:=0) VarSetCapacity(BitmapData, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 diff --git a/ImagePut.ahk b/ImagePut.ahk index b8de7e8f..3a9d8485 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1480,7 +1480,7 @@ class ImagePut { } static from_wicBitmap(image) { - ; IWICBitmapSource::GetSize - https://github.com/tpn/winsdk-10/blob/9b69fd26ac0c7d0b83d378dba01080e93349c2ed/Include/10.0.16299.0/um/wincodec.h#L1304 + ; IWICBitmapSource::GetSize - https://github.com/iseahound/winsdk-10/blob/master/Include/10.0.16299.0/um/wincodec.h#L1304 ComCall(3, image, "uint*", &width:=0, "uint*", &height:=0) ; Intialize an empty pBitmap using managed memory. @@ -1501,7 +1501,7 @@ class ImagePut { Scan0 := NumGet(BitmapData, 16, "ptr") stride := NumGet(BitmapData, 8, "int") - ; IWICBitmapSource::CopyPixels - https://github.com/tpn/winsdk-10/blob/9b69fd26ac0c7d0b83d378dba01080e93349c2ed/Include/10.0.16299.0/um/wincodec.h#L1322 + ; IWICBitmapSource::CopyPixels - https://github.com/iseahound/winsdk-10/blob/master/Include/10.0.16299.0/um/wincodec.h#L1322 ComCall(7, image, "ptr", Rect, "uint", stride, "uint", stride * height, "ptr", Scan0) ; Write pixels to bitmap. @@ -2789,7 +2789,7 @@ class ImagePut { IWICImagingFactory := ComObject(CLSID_WICImagingFactory := "{CACAF262-9370-4615-A13B-9F5539DA4C0A}", IID_IWICImagingFactory := "{EC5EC8A9-C395-4314-9C77-54D7A935FF70}") ; WICBitmapNoCache must be 1! - ; IWICImagingFactory::CreateBitmap - https://github.com/tpn/winsdk-10/blob/9b69fd26ac0c7d0b83d378dba01080e93349c2ed/Include/10.0.16299.0/um/wincodec.h#L6447 + ; IWICImagingFactory::CreateBitmap - https://github.com/iseahound/winsdk-10/blob/master/Include/10.0.16299.0/um/wincodec.h#L6447 DllCall("ole32\CLSIDFromString", "wstr", GUID_WICPixelFormat32bppBGRA := "{6fddc324-4e03-4bfe-b185-3d77768dc90f}", "ptr", CLSID := Buffer(16), "HRESULT") ComCall(17, IWICImagingFactory, "uint", width, "uint", height, "ptr", CLSID, "int", 1, "ptr*", &wicBitmap:=0) @@ -2797,10 +2797,10 @@ class ImagePut { NumPut( "uint", width, Rect, 8) ; Width NumPut( "uint", height, Rect, 12) ; Height - ; IWICBitmap::Lock - https://github.com/tpn/winsdk-10/blob/9b69fd26ac0c7d0b83d378dba01080e93349c2ed/Include/10.0.16299.0/um/wincodec.h#L2232 + ; IWICBitmap::Lock - https://github.com/iseahound/winsdk-10/blob/master/Include/10.0.16299.0/um/wincodec.h#L2232 ComCall(8, wicBitmap, "Ptr", Rect, "uint", 0x1, "ptr*", &Lock:=0) - ; IWICBitmapLock::GetDataPointer - https://github.com/tpn/winsdk-10/blob/9b69fd26ac0c7d0b83d378dba01080e93349c2ed/Include/10.0.16299.0/um/wincodec.h#L2104 + ; IWICBitmapLock::GetDataPointer - https://github.com/iseahound/winsdk-10/blob/master/Include/10.0.16299.0/um/wincodec.h#L2104 ComCall(5, Lock, "uint*", &size:=0, "ptr*", &Scan0:=0) BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 From 08934015fe9a6ebad0de87f621e4b36f1a9ecce0 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 19 Jun 2022 16:00:17 -0400 Subject: [PATCH 305/492] capitalization --- ImagePut (for v1).ahk | 4 ++-- ImagePut.ahk | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 5bd7edf4..319d7c82 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2797,10 +2797,10 @@ class ImagePut { NumPut( height, Rect, 12, "uint") ; Height ; IWICBitmap::Lock - https://github.com/iseahound/winsdk-10/blob/master/Include/10.0.16299.0/um/wincodec.h#L2232 - DllCall(NumGet(NumGet(wicBitmap + 0) + A_PtrSize*8), "Ptr", wicBitmap, "Ptr", &Rect, "uint", 0x1, "ptr*", Lock:=0) + DllCall(NumGet(NumGet(wicBitmap + 0) + A_PtrSize*8), "ptr", wicBitmap, "ptr", &Rect, "uint", 0x1, "ptr*", Lock:=0) ; IWICBitmapLock::GetDataPointer - https://github.com/iseahound/winsdk-10/blob/master/Include/10.0.16299.0/um/wincodec.h#L2104 - DllCall(NumGet(NumGet(Lock + 0) + A_PtrSize*5), "Ptr", Lock, "uint*", size:=0, "ptr*", Scan0:=0) + DllCall(NumGet(NumGet(Lock + 0) + A_PtrSize*5), "ptr", Lock, "uint*", size:=0, "ptr*", Scan0:=0) VarSetCapacity(BitmapData, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 NumPut( 4 * width, BitmapData, 8, "int") ; Stride diff --git a/ImagePut.ahk b/ImagePut.ahk index 3a9d8485..f65eab42 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2798,7 +2798,7 @@ class ImagePut { NumPut( "uint", height, Rect, 12) ; Height ; IWICBitmap::Lock - https://github.com/iseahound/winsdk-10/blob/master/Include/10.0.16299.0/um/wincodec.h#L2232 - ComCall(8, wicBitmap, "Ptr", Rect, "uint", 0x1, "ptr*", &Lock:=0) + ComCall(8, wicBitmap, "ptr", Rect, "uint", 0x1, "ptr*", &Lock:=0) ; IWICBitmapLock::GetDataPointer - https://github.com/iseahound/winsdk-10/blob/master/Include/10.0.16299.0/um/wincodec.h#L2104 ComCall(5, Lock, "uint*", &size:=0, "ptr*", &Scan0:=0) From 7cf9326d575ac5dda968ded6c4d44bf4b29317f2 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 19 Jun 2022 16:35:39 -0400 Subject: [PATCH 306/492] Improve GIF rendering code * Avoid GWLP_USERDATA as it can be set by external programs * Allocate 40 bytes in the window class instead * No more memory leak of lParam --- ImagePut (for v1).ahk | 35 +++++++++++++++++++---------------- ImagePut.ahk | 35 +++++++++++++++++++---------------- 2 files changed, 38 insertions(+), 32 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 319d7c82..604732b3 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2160,19 +2160,22 @@ class ImagePut { ; For multiple frames, send WM_APP to WindowProc to render GIFs. if (frames > 1) { - ; Save frame delays inside GWLP_USERDATA because they are quite slow enough to impact timing. + ; Save frame delays because they are slow enough to impact timing. DllCall("gdiplus\GdipGetPropertyItemSize", "ptr", pBitmap, "uint", 0x5100, "uint*", ItemSize:=0) ; PropertyTagFrameDelay Item := DllCall("GlobalAlloc", "uint", 0, "uptr", ItemSize, "ptr") DllCall("gdiplus\GdipGetPropertyItem", "ptr", pBitmap, "uint", 0x5100, "uint", ItemSize, "ptr", Item) - ; Clone bitmap to avoid disposal, and initiate animation via PostMessage. + ; Clone bitmap to avoid disposal. DllCall("gdiplus\GdipCloneImage", "ptr", pBitmap, "ptr*", pBitmapClone:=0) DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmapClone) - DllCall("SetWindowLongPtr", "ptr", hwnd, "int", GWLP_USERDATA := -21, "ptr", pBitmapClone) - DllCall("PostMessage", "ptr", hwnd, "uint", 0x8000, "uptr", -1, "ptr", Item) + + ; Store data inside window. + DllCall("SetWindowLongPtr", "ptr", hwnd, "int", 0, "ptr", pBitmapClone) + DllCall("SetWindowLongPtr", "ptr", hwnd, "int", 2*A_PtrSize, "ptr", Item) - ; Preserve GDI+ scope. + ; Preserve GDI+ scope and initiate animation via PostMessage. ImagePut.gdiplusStartup() + DllCall("PostMessage", "ptr", hwnd, "uint", 0x8000, "uptr", -1, "ptr", 0) } return hwnd @@ -2200,7 +2203,7 @@ class ImagePut { NumPut( 0x8, wc, 4, "uint") ; style NumPut( pWndProc, wc, 8, "ptr") ; lpfnWndProc NumPut( 0, wc, _ ? 12:16, "int") ; cbClsExtra - NumPut( 0, wc, _ ? 16:20, "int") ; cbWndExtra + NumPut( 40, wc, _ ? 16:20, "int") ; cbWndExtra NumPut( 0, wc, _ ? 20:24, "ptr") ; hInstance NumPut( 0, wc, _ ? 24:32, "ptr") ; hIcon NumPut( hCursor, wc, _ ? 28:40, "ptr") ; hCursor @@ -2227,9 +2230,10 @@ class ImagePut { ; WM_DESTROY if (uMsg = 0x2) { - if pBitmap := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", GWLP_USERDATA := -21, "ptr") { - DllCall("SetWindowLongPtr", "ptr", hwnd, "int", GWLP_USERDATA := -21, "ptr", 0) + if pBitmap := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", 0, "ptr") { + DllCall("SetWindowLongPtr", "ptr", hwnd, "int", 0, "ptr", 0) ; Exit loop. DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + DllCall("GlobalFree", "ptr", DllCall("GetWindowLongPtr", "ptr", hwnd, "int", 2*A_PtrSize, "ptr")) IsObject(ImagePut) && ImagePut.gdiplusShutdown() } Hotkey % "^+F12", % void, Off ; Cannot disable, does nothing @@ -2254,12 +2258,11 @@ class ImagePut { if (uMsg = 0x8000) { Critical ; Thanks Teadrinker - https://www.autohotkey.com/boards/viewtopic.php?f=76&t=83358 + ; Exit Gif loop or get variables. + if !(pBitmap := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", 0, "ptr")) + return + Item := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", 2*A_PtrSize, "ptr") frame := wParam + 1 - Item := lParam - - ; If the window is destroyed... - if !(pBitmap := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", GWLP_USERDATA := -21, "ptr")) - return DllCall("GlobalFree", "ptr", Item) ; Sometimes works. ; Get the next frame and delay. frames := NumGet(Item+0, 4, "uint") // 4 ; Max frames @@ -2284,9 +2287,9 @@ class ImagePut { ; Async the next frame as soon as possible to prevent rendering lag. static pWndProc := RegisterCallback(ImagePut.WindowProc,,, &ImagePut) - next_frame := Func("DllCall").bind(pWndProc, "ptr", hwnd, "uint", uMsg, "uptr", frame, "ptr", Item) + next_frame := Func("DllCall").bind(pWndProc, "ptr", hwnd, "uint", uMsg, "uptr", frame, "ptr", 0) SetTimer % next_frame, % -1 * res - /* + ; Debug code static start := 0, sum := 0, count := 0, sum2 := 0, count2 := 0 DllCall("QueryPerformanceFrequency", "int64*", frequency:=0) @@ -2306,7 +2309,7 @@ class ImagePut { . "`nFloor and Ceiling:`t" Floor(delay / resolution) * resolution ", " Ceil(delay / resolution) * resolution } start := now - */ + ; Select frame to show. DllCall("gdiplus\GdipImageGetFrameDimensionsCount", "ptr", pBitmap, "uint*", dims:=0) DllCall("gdiplus\GdipImageGetFrameDimensionsList", "ptr", pBitmap, "ptr", &dimIDs := VarSetCapacity(dimIDs, 16*dims), "uint", dims) diff --git a/ImagePut.ahk b/ImagePut.ahk index f65eab42..8431d2a2 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2161,19 +2161,22 @@ class ImagePut { ; For multiple frames, send WM_APP to WindowProc to render GIFs. if (frames > 1) { - ; Save frame delays inside GWLP_USERDATA because they are quite slow enough to impact timing. + ; Save frame delays because they are slow enough to impact timing. DllCall("gdiplus\GdipGetPropertyItemSize", "ptr", pBitmap, "uint", 0x5100, "uint*", &ItemSize:=0) ; PropertyTagFrameDelay Item := DllCall("GlobalAlloc", "uint", 0, "uptr", ItemSize, "ptr") DllCall("gdiplus\GdipGetPropertyItem", "ptr", pBitmap, "uint", 0x5100, "uint", ItemSize, "ptr", Item) - ; Clone bitmap to avoid disposal, and initiate animation via PostMessage. + ; Clone bitmap to avoid disposal. DllCall("gdiplus\GdipCloneImage", "ptr", pBitmap, "ptr*", &pBitmapClone:=0) DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmapClone) - DllCall("SetWindowLongPtr", "ptr", hwnd, "int", GWLP_USERDATA := -21, "ptr", pBitmapClone) - DllCall("PostMessage", "ptr", hwnd, "uint", 0x8000, "uptr", -1, "ptr", Item) - ; Preserve GDI+ scope. + ; Store data inside window. + DllCall("SetWindowLongPtr", "ptr", hwnd, "int", 0, "ptr", pBitmapClone) + DllCall("SetWindowLongPtr", "ptr", hwnd, "int", 2*A_PtrSize, "ptr", Item) + + ; Preserve GDI+ scope and initiate animation via PostMessage. ImagePut.gdiplusStartup() + DllCall("PostMessage", "ptr", hwnd, "uint", 0x8000, "uptr", -1, "ptr", 0) } return hwnd @@ -2201,7 +2204,7 @@ class ImagePut { NumPut( "uint", 0x8, wc, 4) ; style NumPut( "ptr", pWndProc, wc, 8) ; lpfnWndProc NumPut( "int", 0, wc, _ ? 12:16) ; cbClsExtra - NumPut( "int", 0, wc, _ ? 16:20) ; cbWndExtra + NumPut( "int", 40, wc, _ ? 16:20) ; cbWndExtra NumPut( "ptr", 0, wc, _ ? 20:24) ; hInstance NumPut( "ptr", 0, wc, _ ? 24:32) ; hIcon NumPut( "ptr", hCursor, wc, _ ? 28:40) ; hCursor @@ -2228,9 +2231,10 @@ class ImagePut { ; WM_DESTROY if (uMsg = 0x2) { - if pBitmap := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", GWLP_USERDATA := -21, "ptr") { - DllCall("SetWindowLongPtr", "ptr", hwnd, "int", GWLP_USERDATA := -21, "ptr", 0) + if pBitmap := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", 0, "ptr") { + DllCall("SetWindowLongPtr", "ptr", hwnd, "int", 0, "ptr", 0) DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + DllCall("GlobalFree", "ptr", DllCall("GetWindowLongPtr", "ptr", hwnd, "int", 2*A_PtrSize, "ptr")) IsObject(ImagePut) && ImagePut.gdiplusShutdown() } Persistent(--active_windows) @@ -2255,12 +2259,11 @@ class ImagePut { if (uMsg = 0x8000) { Critical ; Thanks Teadrinker - https://www.autohotkey.com/boards/viewtopic.php?f=76&t=83358 + ; Exit Gif loop or get variables. + if !(pBitmap := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", 0, "ptr")) + return + Item := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", 2*A_PtrSize, "ptr") frame := wParam + 1 - Item := lParam - - ; If the window is destroyed... - if !(pBitmap := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", GWLP_USERDATA := -21, "ptr")) - return DllCall("GlobalFree", "ptr", Item) ; Sometimes works. ; Get the next frame and delay. frames := NumGet(Item, 4, "uint") // 4 ; Max frames @@ -2284,10 +2287,10 @@ class ImagePut { res := Ceil(delay / resolution) * resolution ; Async the next frame as soon as possible to prevent rendering lag. - SetTimer WindowProc.bind(hwnd, uMsg, frame, Item), -1 * res + SetTimer WindowProc.bind(hwnd, uMsg, frame, 0), -1 * res - /* + ; Debug code static start := 0, sum := 0, count := 0, sum2 := 0, count2 := 0 DllCall("QueryPerformanceFrequency", "int64*", &frequency:=0) @@ -2307,7 +2310,7 @@ class ImagePut { . "`nFloor and Ceiling:`t" Floor(delay / resolution) * resolution ", " Ceil(delay / resolution) * resolution } start := now - */ + ; Select frame to show. DllCall("gdiplus\GdipImageGetFrameDimensionsCount", "ptr", pBitmap, "uint*", &dims:=0) DllCall("gdiplus\GdipImageGetFrameDimensionsList", "ptr", pBitmap, "ptr", dimIDs := Buffer(16*dims), "uint", dims) From 796dc4ddc4c1c0a382d8bbdca74df5e68a9c0ec1 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 19 Jun 2022 17:21:10 -0400 Subject: [PATCH 307/492] Reuse the generated hdc when rendering GIFs --- ImagePut (for v1).ahk | 64 +++++++++++++++++++++++++++++++------------ ImagePut.ahk | 64 +++++++++++++++++++++++++++++++------------ 2 files changed, 92 insertions(+), 36 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 604732b3..9ceed810 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2148,11 +2148,6 @@ class ImagePut { , "uint*", 0xFF << 16 | 0x01 << 24 ; *pblend , "uint", 2) ; dwFlags - ; Cleanup the hBitmap and device contexts. - DllCall("SelectObject", "ptr", hdc, "ptr", obm) - DllCall("DeleteObject", "ptr", hbm) - DllCall("DeleteDC", "ptr", hdc) - ; Check for multiple frames. DllCall("gdiplus\GdipImageGetFrameDimensionsCount", "ptr", pBitmap, "uint*", dims:=0) DllCall("gdiplus\GdipImageGetFrameDimensionsList", "ptr", pBitmap, "ptr", &dimIDs := VarSetCapacity(dimIDs, 16*dims), "uint", dims) @@ -2171,13 +2166,23 @@ class ImagePut { ; Store data inside window. DllCall("SetWindowLongPtr", "ptr", hwnd, "int", 0, "ptr", pBitmapClone) + DllCall("SetWindowLongPtr", "ptr", hwnd, "int", A_PtrSize, "ptr", hdc) DllCall("SetWindowLongPtr", "ptr", hwnd, "int", 2*A_PtrSize, "ptr", Item) - + DllCall("SetWindowLongPtr", "ptr", hwnd, "int", 3*A_PtrSize, "ptr", pBits) + ; Preserve GDI+ scope and initiate animation via PostMessage. ImagePut.gdiplusStartup() DllCall("PostMessage", "ptr", hwnd, "uint", 0x8000, "uptr", -1, "ptr", 0) + + ; Avoid disposing the device context. + return hwnd } + ; Cleanup the hBitmap and device contexts. + DllCall("SelectObject", "ptr", hdc, "ptr", obm) + DllCall("DeleteObject", "ptr", hbm) + DllCall("DeleteDC", "ptr", hdc) + return hwnd } @@ -2231,9 +2236,21 @@ class ImagePut { ; WM_DESTROY if (uMsg = 0x2) { if pBitmap := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", 0, "ptr") { + hdc := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", A_PtrSize, "ptr") + Item := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", 2*A_PtrSize, "ptr") + + ; Exit loop. DllCall("SetWindowLongPtr", "ptr", hwnd, "int", 0, "ptr", 0) ; Exit loop. + + ; Dispose of all data stored in the window class. DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) - DllCall("GlobalFree", "ptr", DllCall("GetWindowLongPtr", "ptr", hwnd, "int", 2*A_PtrSize, "ptr")) + obm := DllCall("CreateBitmap", "int", 0, "int", 0, "uint", 1, "uint", 1, "ptr", 0, "ptr") + hbm := DllCall("SelectObject", "ptr", hdc, "ptr", obm, "ptr") + DllCall("DeleteObject", "ptr", hbm) + DllCall("DeleteDC", "ptr", hdc) + DllCall("GlobalFree", "ptr", Item) + + ; Exit GDI+ conditionally due to the ImagePut class being destroyed first. IsObject(ImagePut) && ImagePut.gdiplusShutdown() } Hotkey % "^+F12", % void, Off ; Cannot disable, does nothing @@ -2256,12 +2273,15 @@ class ImagePut { ; WM_APP - Animate GIFs if (uMsg = 0x8000) { - Critical ; Thanks Teadrinker - https://www.autohotkey.com/boards/viewtopic.php?f=76&t=83358 + ; Thanks tmplinshi, Teadrinker - https://www.autohotkey.com/boards/viewtopic.php?f=76&t=83358 + Critical ; Exit Gif loop or get variables. if !(pBitmap := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", 0, "ptr")) return + hdc := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", A_PtrSize, "ptr") Item := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", 2*A_PtrSize, "ptr") + pBits := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", 3*A_PtrSize, "ptr") frame := wParam + 1 ; Get the next frame and delay. @@ -2289,7 +2309,7 @@ class ImagePut { static pWndProc := RegisterCallback(ImagePut.WindowProc,,, &ImagePut) next_frame := Func("DllCall").bind(pWndProc, "ptr", hwnd, "uint", uMsg, "uptr", frame, "ptr", 0) SetTimer % next_frame, % -1 * res - + ; Debug code static start := 0, sum := 0, count := 0, sum2 := 0, count2 := 0 DllCall("QueryPerformanceFrequency", "int64*", frequency:=0) @@ -2309,7 +2329,7 @@ class ImagePut { . "`nFloor and Ceiling:`t" Floor(delay / resolution) * resolution ", " Ceil(delay / resolution) * resolution } start := now - + ; Select frame to show. DllCall("gdiplus\GdipImageGetFrameDimensionsCount", "ptr", pBitmap, "uint*", dims:=0) DllCall("gdiplus\GdipImageGetFrameDimensionsList", "ptr", pBitmap, "ptr", &dimIDs := VarSetCapacity(dimIDs, 16*dims), "uint", dims) @@ -2319,8 +2339,22 @@ class ImagePut { DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) - ; Render to window. Using put_dc shortens the code. - hdc := ImagePut.put_dc(pBitmap) + ; Transfer data from source pBitmap to an hBitmap manually. + VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 + NumPut( width, Rect, 8, "uint") ; Width + NumPut( height, Rect, 12, "uint") ; Height + VarSetCapacity(BitmapData, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + NumPut( 4 * width, BitmapData, 8, "int") ; Stride + NumPut( pBits, BitmapData, 16, "ptr") ; Scan0 + DllCall("gdiplus\GdipBitmapLockBits" + , "ptr", pBitmap + , "ptr", &Rect + , "uint", 5 ; ImageLockMode.UserInputBuffer | ImageLockMode.ReadOnly + , "int", 0xE200B ; Format32bppPArgb + , "ptr", &BitmapData) ; Contains the pointer (pBits) to the hbm. + DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", &BitmapData) + + ; Render to window. DllCall("UpdateLayeredWindow" , "ptr", hwnd ; hWnd , "ptr", 0 ; hdcDst @@ -2331,12 +2365,6 @@ class ImagePut { , "uint", 0 ; crKey , "uint*", 0xFF << 16 | 0x01 << 24 ; *pblend , "uint", 2) ; dwFlags - - ; Cleanup the hBitmap and device contexts. - obm := DllCall("CreateBitmap", "int", 0, "int", 0, "uint", 1, "uint", 1, "ptr", 0, "ptr") - hbm := DllCall("SelectObject", "ptr", hdc, "ptr", obm, "ptr") - DllCall("DeleteObject", "ptr", hbm) - DllCall("DeleteDC", "ptr", hdc) return } diff --git a/ImagePut.ahk b/ImagePut.ahk index 8431d2a2..e10adfda 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2149,11 +2149,6 @@ class ImagePut { , "uint*", 0xFF << 16 | 0x01 << 24 ; *pblend , "uint", 2) ; dwFlags - ; Cleanup the hBitmap and device contexts. - DllCall("SelectObject", "ptr", hdc, "ptr", obm) - DllCall("DeleteObject", "ptr", hbm) - DllCall("DeleteDC", "ptr", hdc) - ; Check for multiple frames. DllCall("gdiplus\GdipImageGetFrameDimensionsCount", "ptr", pBitmap, "uint*", &dims:=0) DllCall("gdiplus\GdipImageGetFrameDimensionsList", "ptr", pBitmap, "ptr", dimIDs := Buffer(16*dims), "uint", dims) @@ -2172,13 +2167,23 @@ class ImagePut { ; Store data inside window. DllCall("SetWindowLongPtr", "ptr", hwnd, "int", 0, "ptr", pBitmapClone) + DllCall("SetWindowLongPtr", "ptr", hwnd, "int", A_PtrSize, "ptr", hdc) DllCall("SetWindowLongPtr", "ptr", hwnd, "int", 2*A_PtrSize, "ptr", Item) + DllCall("SetWindowLongPtr", "ptr", hwnd, "int", 3*A_PtrSize, "ptr", pBits) ; Preserve GDI+ scope and initiate animation via PostMessage. ImagePut.gdiplusStartup() DllCall("PostMessage", "ptr", hwnd, "uint", 0x8000, "uptr", -1, "ptr", 0) + + ; Avoid disposing the device context. + return hwnd } + ; Cleanup the hBitmap and device contexts. + DllCall("SelectObject", "ptr", hdc, "ptr", obm) + DllCall("DeleteObject", "ptr", hbm) + DllCall("DeleteDC", "ptr", hdc) + return hwnd } @@ -2232,9 +2237,21 @@ class ImagePut { ; WM_DESTROY if (uMsg = 0x2) { if pBitmap := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", 0, "ptr") { + hdc := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", A_PtrSize, "ptr") + Item := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", 2*A_PtrSize, "ptr") + + ; Exit loop. DllCall("SetWindowLongPtr", "ptr", hwnd, "int", 0, "ptr", 0) + + ; Dispose of all data stored in the window class. DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) - DllCall("GlobalFree", "ptr", DllCall("GetWindowLongPtr", "ptr", hwnd, "int", 2*A_PtrSize, "ptr")) + obm := DllCall("CreateBitmap", "int", 0, "int", 0, "uint", 1, "uint", 1, "ptr", 0, "ptr") + hbm := DllCall("SelectObject", "ptr", hdc, "ptr", obm, "ptr") + DllCall("DeleteObject", "ptr", hbm) + DllCall("DeleteDC", "ptr", hdc) + DllCall("GlobalFree", "ptr", Item) + + ; Exit GDI+ conditionally due to the ImagePut class being destroyed first. IsObject(ImagePut) && ImagePut.gdiplusShutdown() } Persistent(--active_windows) @@ -2257,12 +2274,15 @@ class ImagePut { ; WM_APP - Animate GIFs if (uMsg = 0x8000) { - Critical ; Thanks Teadrinker - https://www.autohotkey.com/boards/viewtopic.php?f=76&t=83358 - + ; Thanks tmplinshi, Teadrinker - https://www.autohotkey.com/boards/viewtopic.php?f=76&t=83358 + Critical + ; Exit Gif loop or get variables. if !(pBitmap := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", 0, "ptr")) return + hdc := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", A_PtrSize, "ptr") Item := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", 2*A_PtrSize, "ptr") + pBits := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", 3*A_PtrSize, "ptr") frame := wParam + 1 ; Get the next frame and delay. @@ -2290,7 +2310,7 @@ class ImagePut { SetTimer WindowProc.bind(hwnd, uMsg, frame, 0), -1 * res - + ; Debug code static start := 0, sum := 0, count := 0, sum2 := 0, count2 := 0 DllCall("QueryPerformanceFrequency", "int64*", &frequency:=0) @@ -2310,7 +2330,7 @@ class ImagePut { . "`nFloor and Ceiling:`t" Floor(delay / resolution) * resolution ", " Ceil(delay / resolution) * resolution } start := now - + ; Select frame to show. DllCall("gdiplus\GdipImageGetFrameDimensionsCount", "ptr", pBitmap, "uint*", &dims:=0) DllCall("gdiplus\GdipImageGetFrameDimensionsList", "ptr", pBitmap, "ptr", dimIDs := Buffer(16*dims), "uint", dims) @@ -2320,8 +2340,22 @@ class ImagePut { DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) - ; Render to window. Using put_dc shortens the code. - hdc := this.put_dc(pBitmap) + ; Transfer data from source pBitmap to an hBitmap manually. + Rect := Buffer(16, 0) ; sizeof(Rect) = 16 + NumPut( "uint", width, Rect, 8) ; Width + NumPut( "uint", height, Rect, 12) ; Height + BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + NumPut( "int", 4 * width, BitmapData, 8) ; Stride + NumPut( "ptr", pBits, BitmapData, 16) ; Scan0 + DllCall("gdiplus\GdipBitmapLockBits" + , "ptr", pBitmap + , "ptr", Rect + , "uint", 5 ; ImageLockMode.UserInputBuffer | ImageLockMode.ReadOnly + , "int", 0xE200B ; Format32bppPArgb + , "ptr", BitmapData) ; Contains the pointer (pBits) to the hbm. + DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", BitmapData) + + ; Render to window. DllCall("UpdateLayeredWindow" , "ptr", hwnd ; hWnd , "ptr", 0 ; hdcDst @@ -2332,12 +2366,6 @@ class ImagePut { , "uint", 0 ; crKey , "uint*", 0xFF << 16 | 0x01 << 24 ; *pblend , "uint", 2) ; dwFlags - - ; Cleanup the hBitmap and device contexts. - obm := DllCall("CreateBitmap", "int", 0, "int", 0, "uint", 1, "uint", 1, "ptr", 0, "ptr") - hbm := DllCall("SelectObject", "ptr", hdc, "ptr", obm, "ptr") - DllCall("DeleteObject", "ptr", hbm) - DllCall("DeleteDC", "ptr", hdc) return } From 2c943249027a5eb837bafdfbce114e22f4b31913 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 19 Jun 2022 18:52:48 -0400 Subject: [PATCH 308/492] comments --- ImagePut (for v1).ahk | 6 ++++-- ImagePut.ahk | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 9ceed810..fe341b64 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2164,14 +2164,16 @@ class ImagePut { DllCall("gdiplus\GdipCloneImage", "ptr", pBitmap, "ptr*", pBitmapClone:=0) DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmapClone) - ; Store data inside window. + ; Store data inside window class extra bits (cbWndExtra). DllCall("SetWindowLongPtr", "ptr", hwnd, "int", 0, "ptr", pBitmapClone) DllCall("SetWindowLongPtr", "ptr", hwnd, "int", A_PtrSize, "ptr", hdc) DllCall("SetWindowLongPtr", "ptr", hwnd, "int", 2*A_PtrSize, "ptr", Item) DllCall("SetWindowLongPtr", "ptr", hwnd, "int", 3*A_PtrSize, "ptr", pBits) - ; Preserve GDI+ scope and initiate animation via PostMessage. + ; Preserve GDI+ scope. ImagePut.gdiplusStartup() + + ; Goto WindowProc() and initiate animation via PostMessage. DllCall("PostMessage", "ptr", hwnd, "uint", 0x8000, "uptr", -1, "ptr", 0) ; Avoid disposing the device context. diff --git a/ImagePut.ahk b/ImagePut.ahk index e10adfda..6a4ffd05 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2165,14 +2165,16 @@ class ImagePut { DllCall("gdiplus\GdipCloneImage", "ptr", pBitmap, "ptr*", &pBitmapClone:=0) DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmapClone) - ; Store data inside window. + ; Store data inside window class extra bits (cbWndExtra). DllCall("SetWindowLongPtr", "ptr", hwnd, "int", 0, "ptr", pBitmapClone) DllCall("SetWindowLongPtr", "ptr", hwnd, "int", A_PtrSize, "ptr", hdc) DllCall("SetWindowLongPtr", "ptr", hwnd, "int", 2*A_PtrSize, "ptr", Item) DllCall("SetWindowLongPtr", "ptr", hwnd, "int", 3*A_PtrSize, "ptr", pBits) - ; Preserve GDI+ scope and initiate animation via PostMessage. + ; Preserve GDI+ scope. ImagePut.gdiplusStartup() + + ; Goto WindowProc() and initiate animation via PostMessage. DllCall("PostMessage", "ptr", hwnd, "uint", 0x8000, "uptr", -1, "ptr", 0) ; Avoid disposing the device context. From 31a514a92069a459904b5ec20b4eb127359c9b33 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 19 Jun 2022 18:53:54 -0400 Subject: [PATCH 309/492] disable debug mode --- ImagePut (for v1).ahk | 4 ++-- ImagePut.ahk | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index fe341b64..0e1cd981 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2311,7 +2311,7 @@ class ImagePut { static pWndProc := RegisterCallback(ImagePut.WindowProc,,, &ImagePut) next_frame := Func("DllCall").bind(pWndProc, "ptr", hwnd, "uint", uMsg, "uptr", frame, "ptr", 0) SetTimer % next_frame, % -1 * res - + /* ; Debug code static start := 0, sum := 0, count := 0, sum2 := 0, count2 := 0 DllCall("QueryPerformanceFrequency", "int64*", frequency:=0) @@ -2331,7 +2331,7 @@ class ImagePut { . "`nFloor and Ceiling:`t" Floor(delay / resolution) * resolution ", " Ceil(delay / resolution) * resolution } start := now - + */ ; Select frame to show. DllCall("gdiplus\GdipImageGetFrameDimensionsCount", "ptr", pBitmap, "uint*", dims:=0) DllCall("gdiplus\GdipImageGetFrameDimensionsList", "ptr", pBitmap, "ptr", &dimIDs := VarSetCapacity(dimIDs, 16*dims), "uint", dims) diff --git a/ImagePut.ahk b/ImagePut.ahk index 6a4ffd05..b1f6bc72 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2312,7 +2312,7 @@ class ImagePut { SetTimer WindowProc.bind(hwnd, uMsg, frame, 0), -1 * res - + /* ; Debug code static start := 0, sum := 0, count := 0, sum2 := 0, count2 := 0 DllCall("QueryPerformanceFrequency", "int64*", &frequency:=0) @@ -2332,7 +2332,7 @@ class ImagePut { . "`nFloor and Ceiling:`t" Floor(delay / resolution) * resolution ", " Ceil(delay / resolution) * resolution } start := now - + */ ; Select frame to show. DllCall("gdiplus\GdipImageGetFrameDimensionsCount", "ptr", pBitmap, "uint*", &dims:=0) DllCall("gdiplus\GdipImageGetFrameDimensionsList", "ptr", pBitmap, "ptr", dimIDs := Buffer(16*dims), "uint", dims) From fdca7e821cdfa4bf85d47585f2045a56f6906879 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 20 Jun 2022 18:51:44 -0400 Subject: [PATCH 310/492] Prettify machine code --- ImagePut (for v1).ahk | 48 +++++++++++++++++++++---------------------- ImagePut.ahk | 48 +++++++++++++++++++++---------------------- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 0e1cd981..a36ff120 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1777,49 +1777,49 @@ class ImagePut { ColorKey(key := 0xFFFFFFFF, value := 0x00000000) { ; C source code - https://godbolt.org/z/eaG9fax9v - static bin := 0, code := (A_PtrSize == 4) + static code := 0 + (!code) && code := this.Base64Put((A_PtrSize == 4) ? "VYnli0UIi1UQi00UO0UMcws5EHUCiQiDwATr8F3D" - : "SDnRcw5EOQF1A0SJCUiDwQTr7cM=" - (!bin) && bin := this.Base64Put(code) + : "SDnRcw5EOQF1A0SJCUiDwQTr7cM=") ; Replaces one ARGB color with another. - DllCall(bin, "ptr", this.ptr, "uint", this.ptr + this.size, "uint", key, "uint", value) + DllCall(code, "ptr", this.ptr, "uint", this.ptr + this.size, "uint", key, "uint", value) } SetAlpha(alpha := 0xFF) { ; C source code - https://godbolt.org/z/aWf73jTqc - static bin := 0, code := (A_PtrSize == 4) + static code := 0 + (!code) && code := this.Base64Put((A_PtrSize == 4) ? "VYnli0UIilUQO0UMcwiIUAODwATr813D" - : "SDnRcwpEiEEDSIPBBOvxww==" - (!bin) && bin := this.Base64Put(code) + : "SDnRcwpEiEEDSIPBBOvxww==") ; Sets the transparency of the entire bitmap. - DllCall(bin, "ptr", this.ptr, "ptr", this.ptr + this.size, "uchar", alpha) + DllCall(code, "ptr", this.ptr, "ptr", this.ptr + this.size, "uchar", alpha) } TransColor(color := 0xFFFFFF, alpha := 0x00) { ; C source code - https://godbolt.org/z/z3a8WcM5M - static bin := 0, code := (A_PtrSize == 4) + static code := 0 + (!code) && code := this.Base64Put((A_PtrSize == 4) ? "VYnli0UIilUUO0UMcxWLTRAzCIHh////AHUDiFADg8AE6+Zdww==" - : "SDnRcxaLAUQxwKn///8AdQREiEkDSIPBBOvlww==" - (!bin) && bin := this.Base64Put(code) + : "SDnRcxaLAUQxwKn///8AdQREiEkDSIPBBOvlww==") ; Sets the alpha value of a specified RGB color. - DllCall(bin, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "uchar", alpha) + DllCall(code, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "uchar", alpha) } PixelSearch(color) { ; C source code - https://godbolt.org/z/o7EPo8xPr - static bin := 0, code := (A_PtrSize == 4) + static code := 0 + (!code) && code := this.Base64Put((A_PtrSize == 4) ? "VYnli1UMi00Qi0UIOdBzCTkIdAeDwATr84nQXcM=" - : "SInISDnQcwtEOQB0CUiDwATr8EiJ0MM=" - (!bin) && bin := this.Base64Put(code) + : "SInISDnQcwtEOQB0CUiDwATr8EiJ0MM=") ; Lift color to 32-bits if first 8 bits are zero. (!(color >> 24)) && color |= 0xFF000000 ; Get the address of the first matching pixel. - byte := DllCall(bin, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "ptr") + byte := DllCall(code, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "ptr") ; Compare the address to the out-of-bounds limit. if (byte == this.ptr + this.size) @@ -1832,10 +1832,10 @@ class ImagePut { PixelSearch2(color, variation := 3) { ; C source code - https://godbolt.org/z/oocoPndE8 - static bin := 0, code := (A_PtrSize == 4) + static code := 0 + (!code) && code := this.Base64Put((A_PtrSize == 4) ? "VYnlVlNRikUQilUcik0gil0ki3UIiEX3ikUUiEX2ikUYiEX1O3UMcyiKRgI6Rfd3GzpF9nIWikYBOkX1dw440HIKigY4yHcEONhzCIPGBOvTi3UMWonwW15dww==" - : "VlNEilQkOESKXCRAilwkSECKdCRQSInISDnQcyuKSAJEOMF3HUQ4yXIYikgBRDjRdxBEONlyC4oIONl3BUA48XMJSIPABOvQSInQW17D" - (!bin) && bin := this.Base64Put(code) + : "VlNEilQkOESKXCRAilwkSECKdCRQSInISDnQcyuKSAJEOMF3HUQ4yXIYikgBRDjRdxBEONlyC4oIONl3BUA48XMJSIPABOvQSInQW17D") v := variation r := ((color & 0xFF0000) >> 16) @@ -1843,7 +1843,7 @@ class ImagePut { b := ((color & 0xFF)) ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. - byte := DllCall(bin, "ptr", this.ptr, "ptr", this.ptr + this.size + byte := DllCall(code, "ptr", this.ptr, "ptr", this.ptr + this.size , "uchar", Min(r+v, 255) , "uchar", Max(r-v, 0) , "uchar", Min(g+v, 255) @@ -1863,20 +1863,20 @@ class ImagePut { ImageSearch(image) { ; C source code - https://godbolt.org/z/q1rxvx38Y - static bin := 0, code := (A_PtrSize == 4) + static code := 0 + (!code) && code := this.Base64Put((A_PtrSize == 4) ? "VYnlV1ZTg+wUi1UYi3UUi0UQi30MjTSWi00MiXXoi3UcjRyFAAAAACnXK0UcD6/LA00IiX3kweYCiUXgiXXsiU3wi00IO03wc0yL" . "RRSLADkBdT6JyCtFCDHSwfgC93UMOVXkfiw5ReB+J4tFFInKMf87fRx0IztF6HMOizI5MHUQg8IEg8AE6+0B2gNF7Efr4IPBBOuv" . "i03wg8QUichbXl9dww==" : "QVdBVkFVQVRVV1ZTi0QkaIt0JHBIifdIweYCSYnLidFEicNBD6/QQYnNSMHjAk2J2kEpxUEp+EmNLJOJwk2NJJFJOepzVkGLAUE5" . "AnVITInQMdJMKdhIwfgC9/FBOdV+NUE5wH4wTInSTInIRTH2QTn+dCtMOeBzEkSLOkQ5OHUVSIPCBEiDwATr6UgB2kgB8EH/xuvZ" - . "SYPCBOulSYnqTInQW15fXUFcQV1BXkFfww==" - (!bin) && bin := this.Base64Put(code) + . "SYPCBOulSYnqTInQW15fXUFcQV1BXkFfww==") if ImagePut.ImageType(image) != "buffer" image := ImagePutBuffer(image) ; Search for the address of the first matching image. - byte := DllCall(bin, "ptr", this.ptr, "uint", this.width, "uint", this.height + byte := DllCall(code, "ptr", this.ptr, "uint", this.width, "uint", this.height , "ptr", image.ptr, "uint", image.width, "uint", image.height, "ptr") ; Compare the address to the out-of-bounds limit. diff --git a/ImagePut.ahk b/ImagePut.ahk index b1f6bc72..d4f525fb 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1778,49 +1778,49 @@ class ImagePut { ColorKey(key := 0xFFFFFFFF, value := 0x00000000) { ; C source code - https://godbolt.org/z/eaG9fax9v - static bin := 0, code := (A_PtrSize == 4) + static code := 0 + (!code) && code := this.Base64Put((A_PtrSize == 4) ? "VYnli0UIi1UQi00UO0UMcws5EHUCiQiDwATr8F3D" - : "SDnRcw5EOQF1A0SJCUiDwQTr7cM=" - (!bin) && bin := this.Base64Put(code) + : "SDnRcw5EOQF1A0SJCUiDwQTr7cM=") ; Replaces one ARGB color with another. - DllCall(bin, "ptr", this.ptr, "uint", this.ptr + this.size, "uint", key, "uint", value) + DllCall(code, "ptr", this.ptr, "uint", this.ptr + this.size, "uint", key, "uint", value) } SetAlpha(alpha := 0xFF) { ; C source code - https://godbolt.org/z/aWf73jTqc - static bin := 0, code := (A_PtrSize == 4) + static code := 0 + (!code) && code := this.Base64Put((A_PtrSize == 4) ? "VYnli0UIilUQO0UMcwiIUAODwATr813D" - : "SDnRcwpEiEEDSIPBBOvxww==" - (!bin) && bin := this.Base64Put(code) + : "SDnRcwpEiEEDSIPBBOvxww==") ; Sets the transparency of the entire bitmap. - DllCall(bin, "ptr", this.ptr, "ptr", this.ptr + this.size, "uchar", alpha) + DllCall(code, "ptr", this.ptr, "ptr", this.ptr + this.size, "uchar", alpha) } TransColor(color := 0xFFFFFF, alpha := 0x00) { ; C source code - https://godbolt.org/z/z3a8WcM5M - static bin := 0, code := (A_PtrSize == 4) + static code := 0 + (!code) && code := this.Base64Put((A_PtrSize == 4) ? "VYnli0UIilUUO0UMcxWLTRAzCIHh////AHUDiFADg8AE6+Zdww==" - : "SDnRcxaLAUQxwKn///8AdQREiEkDSIPBBOvlww==" - (!bin) && bin := this.Base64Put(code) + : "SDnRcxaLAUQxwKn///8AdQREiEkDSIPBBOvlww==") ; Sets the alpha value of a specified RGB color. - DllCall(bin, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "uchar", alpha) + DllCall(code, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "uchar", alpha) } PixelSearch(color) { ; C source code - https://godbolt.org/z/o7EPo8xPr - static bin := 0, code := (A_PtrSize == 4) + static code := 0 + (!code) && code := this.Base64Put((A_PtrSize == 4) ? "VYnli1UMi00Qi0UIOdBzCTkIdAeDwATr84nQXcM=" - : "SInISDnQcwtEOQB0CUiDwATr8EiJ0MM=" - (!bin) && bin := this.Base64Put(code) + : "SInISDnQcwtEOQB0CUiDwATr8EiJ0MM=") ; Lift color to 32-bits if first 8 bits are zero. (!(color >> 24)) && color |= 0xFF000000 ; Get the address of the first matching pixel. - byte := DllCall(bin, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "ptr") + byte := DllCall(code, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "ptr") ; Compare the address to the out-of-bounds limit. if (byte == this.ptr + this.size) @@ -1833,10 +1833,10 @@ class ImagePut { PixelSearch2(color, variation := 3) { ; C source code - https://godbolt.org/z/oocoPndE8 - static bin := 0, code := (A_PtrSize == 4) + static code := 0 + (!code) && code := this.Base64Put((A_PtrSize == 4) ? "VYnlVlNRikUQilUcik0gil0ki3UIiEX3ikUUiEX2ikUYiEX1O3UMcyiKRgI6Rfd3GzpF9nIWikYBOkX1dw440HIKigY4yHcEONhzCIPGBOvTi3UMWonwW15dww==" - : "VlNEilQkOESKXCRAilwkSECKdCRQSInISDnQcyuKSAJEOMF3HUQ4yXIYikgBRDjRdxBEONlyC4oIONl3BUA48XMJSIPABOvQSInQW17D" - (!bin) && bin := this.Base64Put(code) + : "VlNEilQkOESKXCRAilwkSECKdCRQSInISDnQcyuKSAJEOMF3HUQ4yXIYikgBRDjRdxBEONlyC4oIONl3BUA48XMJSIPABOvQSInQW17D") v := variation r := ((color & 0xFF0000) >> 16) @@ -1844,7 +1844,7 @@ class ImagePut { b := ((color & 0xFF)) ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. - byte := DllCall(bin, "ptr", this.ptr, "ptr", this.ptr + this.size + byte := DllCall(code, "ptr", this.ptr, "ptr", this.ptr + this.size , "uchar", Min(r+v, 255) , "uchar", Max(r-v, 0) , "uchar", Min(g+v, 255) @@ -1864,20 +1864,20 @@ class ImagePut { ImageSearch(image) { ; C source code - https://godbolt.org/z/q1rxvx38Y - static bin := 0, code := (A_PtrSize == 4) + static code := 0 + (!code) && code := this.Base64Put((A_PtrSize == 4) ? "VYnlV1ZTg+wUi1UYi3UUi0UQi30MjTSWi00MiXXoi3UcjRyFAAAAACnXK0UcD6/LA00IiX3kweYCiUXgiXXsiU3wi00IO03wc0yL" . "RRSLADkBdT6JyCtFCDHSwfgC93UMOVXkfiw5ReB+J4tFFInKMf87fRx0IztF6HMOizI5MHUQg8IEg8AE6+0B2gNF7Efr4IPBBOuv" . "i03wg8QUichbXl9dww==" : "QVdBVkFVQVRVV1ZTi0QkaIt0JHBIifdIweYCSYnLidFEicNBD6/QQYnNSMHjAk2J2kEpxUEp+EmNLJOJwk2NJJFJOepzVkGLAUE5" . "AnVITInQMdJMKdhIwfgC9/FBOdV+NUE5wH4wTInSTInIRTH2QTn+dCtMOeBzEkSLOkQ5OHUVSIPCBEiDwATr6UgB2kgB8EH/xuvZ" - . "SYPCBOulSYnqTInQW15fXUFcQV1BXkFfww==" - (!bin) && bin := this.Base64Put(code) + . "SYPCBOulSYnqTInQW15fXUFcQV1BXkFfww==") if ImagePut.ImageType(image) != "buffer" image := ImagePutBuffer(image) ; Search for the address of the first matching image. - byte := DllCall(bin, "ptr", this.ptr, "uint", this.width, "uint", this.height + byte := DllCall(code, "ptr", this.ptr, "uint", this.width, "uint", this.height , "ptr", image.ptr, "uint", image.width, "uint", image.height, "ptr") ; Compare the address to the out-of-bounds limit. From aa0b695583a9eeba663513897ccfd66b44a48f90 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 20 Jun 2022 18:53:23 -0400 Subject: [PATCH 311/492] Avoid GdiplusShutdown error on Reload --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index a36ff120..73a5ae41 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1703,7 +1703,7 @@ class ImagePut { __Delete() { DllCall("gdiplus\GdipDisposeImage", "ptr", this.pBitmap) DllCall("GlobalFree", "ptr", this.ptr) - ImagePut.gdiplusShutdown() + IsObject(ImagePut) && ImagePut.gdiplusShutdown() } __Get(x, y) { diff --git a/ImagePut.ahk b/ImagePut.ahk index d4f525fb..4e6b890a 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1704,7 +1704,7 @@ class ImagePut { __Delete() { DllCall("gdiplus\GdipDisposeImage", "ptr", this.pBitmap) DllCall("GlobalFree", "ptr", this.ptr) - ImagePut.gdiplusShutdown() + IsObject(ImagePut) && ImagePut.gdiplusShutdown() } __Item[x, y] { From 0b75fdeb720ad2a029f1cb9e5c658215d54782ed Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 20 Jun 2022 19:11:27 -0400 Subject: [PATCH 312/492] Combine PixelSearch and PixelSearch2 --- ImagePut (for v1).ahk | 89 +++++++++++++++++++++++-------------------- ImagePut.ahk | 89 +++++++++++++++++++++++-------------------- 2 files changed, 94 insertions(+), 84 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 73a5ae41..c6b69231 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1808,57 +1808,62 @@ class ImagePut { DllCall(code, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "uchar", alpha) } - PixelSearch(color) { + PixelSearch(color, variation := 0) { ; C source code - https://godbolt.org/z/o7EPo8xPr - static code := 0 - (!code) && code := this.Base64Put((A_PtrSize == 4) + static PixelSearch := 0 + (!PixelSearch) && PixelSearch := this.Base64Put((A_PtrSize == 4) ? "VYnli1UMi00Qi0UIOdBzCTkIdAeDwATr84nQXcM=" : "SInISDnQcwtEOQB0CUiDwATr8EiJ0MM=") - ; Lift color to 32-bits if first 8 bits are zero. - (!(color >> 24)) && color |= 0xFF000000 - - ; Get the address of the first matching pixel. - byte := DllCall(code, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "ptr") - - ; Compare the address to the out-of-bounds limit. - if (byte == this.ptr + this.size) - return False - - ; Return an [x, y] array. - offset := (byte - this.ptr) // 4 - return [mod(offset, this.width), offset // this.width] - } - - PixelSearch2(color, variation := 3) { ; C source code - https://godbolt.org/z/oocoPndE8 - static code := 0 - (!code) && code := this.Base64Put((A_PtrSize == 4) + static PixelSearch2 := 0 + (!PixelSearch2) && PixelSearch2 := this.Base64Put((A_PtrSize == 4) ? "VYnlVlNRikUQilUcik0gil0ki3UIiEX3ikUUiEX2ikUYiEX1O3UMcyiKRgI6Rfd3GzpF9nIWikYBOkX1dw440HIKigY4yHcEONhzCIPGBOvTi3UMWonwW15dww==" : "VlNEilQkOESKXCRAilwkSECKdCRQSInISDnQcyuKSAJEOMF3HUQ4yXIYikgBRDjRdxBEONlyC4oIONl3BUA48XMJSIPABOvQSInQW17D") - v := variation - r := ((color & 0xFF0000) >> 16) - g := ((color & 0xFF00) >> 8) - b := ((color & 0xFF)) - - ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. - byte := DllCall(code, "ptr", this.ptr, "ptr", this.ptr + this.size - , "uchar", Min(r+v, 255) - , "uchar", Max(r-v, 0) - , "uchar", Min(g+v, 255) - , "uchar", Max(g-v, 0) - , "uchar", Min(b+v, 255) - , "uchar", Max(b-v, 0) - , "ptr") - - ; Compare the address to the out-of-bounds limit. - if (byte == this.ptr + this.size) - return False + ; Lift color to 32-bits if first 8 bits are zero. + (!(color >> 24)) && color |= 0xFF000000 - ; Return an [x, y] array. - offset := (byte - this.ptr) // 4 - return [mod(offset, this.width), offset // this.width] + ; PixelSearch, no variation, no range + if (variation <= 0) { + + ; Get the address of the first matching pixel. + byte := DllCall(PixelSearch, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "ptr") + + ; Compare the address to the out-of-bounds limit. + if (byte == this.ptr + this.size) + return False + + ; Return an [x, y] array. + offset := (byte - this.ptr) // 4 + return [mod(offset, this.width), offset // this.width] + } + + ; PixelSearch with variation + else { + v := variation + r := ((color & 0xFF0000) >> 16) + g := ((color & 0xFF00) >> 8) + b := ((color & 0xFF)) + + ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. + byte := DllCall(PixelSearch2, "ptr", this.ptr, "ptr", this.ptr + this.size + , "uchar", Min(r+v, 255) + , "uchar", Max(r-v, 0) + , "uchar", Min(g+v, 255) + , "uchar", Max(g-v, 0) + , "uchar", Min(b+v, 255) + , "uchar", Max(b-v, 0) + , "ptr") + + ; Compare the address to the out-of-bounds limit. + if (byte == this.ptr + this.size) + return False + + ; Return an [x, y] array. + offset := (byte - this.ptr) // 4 + return [mod(offset, this.width), offset // this.width] + } } ImageSearch(image) { diff --git a/ImagePut.ahk b/ImagePut.ahk index 4e6b890a..91b9298e 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1809,57 +1809,62 @@ class ImagePut { DllCall(code, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "uchar", alpha) } - PixelSearch(color) { + PixelSearch(color, variation := 0) { ; C source code - https://godbolt.org/z/o7EPo8xPr - static code := 0 - (!code) && code := this.Base64Put((A_PtrSize == 4) + static PixelSearch := 0 + (!PixelSearch) && PixelSearch := this.Base64Put((A_PtrSize == 4) ? "VYnli1UMi00Qi0UIOdBzCTkIdAeDwATr84nQXcM=" : "SInISDnQcwtEOQB0CUiDwATr8EiJ0MM=") - ; Lift color to 32-bits if first 8 bits are zero. - (!(color >> 24)) && color |= 0xFF000000 - - ; Get the address of the first matching pixel. - byte := DllCall(code, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "ptr") - - ; Compare the address to the out-of-bounds limit. - if (byte == this.ptr + this.size) - return False - - ; Return an [x, y] array. - offset := (byte - this.ptr) // 4 - return [mod(offset, this.width), offset // this.width] - } - - PixelSearch2(color, variation := 3) { ; C source code - https://godbolt.org/z/oocoPndE8 - static code := 0 - (!code) && code := this.Base64Put((A_PtrSize == 4) + static PixelSearch2 := 0 + (!PixelSearch2) && PixelSearch2 := this.Base64Put((A_PtrSize == 4) ? "VYnlVlNRikUQilUcik0gil0ki3UIiEX3ikUUiEX2ikUYiEX1O3UMcyiKRgI6Rfd3GzpF9nIWikYBOkX1dw440HIKigY4yHcEONhzCIPGBOvTi3UMWonwW15dww==" : "VlNEilQkOESKXCRAilwkSECKdCRQSInISDnQcyuKSAJEOMF3HUQ4yXIYikgBRDjRdxBEONlyC4oIONl3BUA48XMJSIPABOvQSInQW17D") - v := variation - r := ((color & 0xFF0000) >> 16) - g := ((color & 0xFF00) >> 8) - b := ((color & 0xFF)) - - ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. - byte := DllCall(code, "ptr", this.ptr, "ptr", this.ptr + this.size - , "uchar", Min(r+v, 255) - , "uchar", Max(r-v, 0) - , "uchar", Min(g+v, 255) - , "uchar", Max(g-v, 0) - , "uchar", Min(b+v, 255) - , "uchar", Max(b-v, 0) - , "ptr") - - ; Compare the address to the out-of-bounds limit. - if (byte == this.ptr + this.size) - return False + ; Lift color to 32-bits if first 8 bits are zero. + (!(color >> 24)) && color |= 0xFF000000 - ; Return an [x, y] array. - offset := (byte - this.ptr) // 4 - return [mod(offset, this.width), offset // this.width] + ; PixelSearch, no variation, no range + if (variation <= 0) { + + ; Get the address of the first matching pixel. + byte := DllCall(PixelSearch, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "ptr") + + ; Compare the address to the out-of-bounds limit. + if (byte == this.ptr + this.size) + return False + + ; Return an [x, y] array. + offset := (byte - this.ptr) // 4 + return [mod(offset, this.width), offset // this.width] + } + + ; PixelSearch with variation + else { + v := variation + r := ((color & 0xFF0000) >> 16) + g := ((color & 0xFF00) >> 8) + b := ((color & 0xFF)) + + ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. + byte := DllCall(PixelSearch2, "ptr", this.ptr, "ptr", this.ptr + this.size + , "uchar", Min(r+v, 255) + , "uchar", Max(r-v, 0) + , "uchar", Min(g+v, 255) + , "uchar", Max(g-v, 0) + , "uchar", Min(b+v, 255) + , "uchar", Max(b-v, 0) + , "ptr") + + ; Compare the address to the out-of-bounds limit. + if (byte == this.ptr + this.size) + return False + + ; Return an [x, y] array. + offset := (byte - this.ptr) // 4 + return [mod(offset, this.width), offset // this.width] + } } ImageSearch(image) { From 8b99bdf33dec5d2ce307b832ea8e99d6b9f8bdf3 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 25 Jun 2022 21:16:51 -0400 Subject: [PATCH 313/492] DirectX screen capture --- ImagePut.ahk | 214 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) diff --git a/ImagePut.ahk b/ImagePut.ahk index 91b9298e..8b90dfbd 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -827,6 +827,220 @@ class ImagePut { ; to do } + static read_screen() { + + assert(statement, message) { + if !statement + throw ValueError(message, -1, statement) + } + + ; Load DirectX + assert IDXGIFactory := CreateDXGIFactory(), "Create IDXGIFactory failed." + + CreateDXGIFactory() { + if !DllCall("GetModuleHandle", "str", "DXGI") + DllCall("LoadLibrary", "str", "DXGI") + if !DllCall("GetModuleHandle", "str", "D3D11") + DllCall("LoadLibrary", "str", "D3D11") + DllCall("ole32\CLSIDFromString", "wstr", "{7b7166ec-21c7-44ae-b21a-c9ae321ae369}", "ptr", riid := Buffer(16, 0), "HRESULT") + DllCall("DXGI\CreateDXGIFactory1", "ptr", riid, "ptr*", &ppFactory:=0, "HRESULT") + return ppFactory + } + + ; Get monitor? + loop { + ComCall(IDXGIFactory_EnumAdapters := 7, IDXGIFactory, "uint", A_Index-1, "ptr*", &IDXGIAdapter:=0) + + loop { + try ComCall(IDXGIAdapter_EnumOutputs := 7, IDXGIAdapter, "uint", A_Index-1, "ptr*", &IDXGIOutput:=0) + catch OSError as e + if e.number = 0x887A0002 ; DXGI_ERROR_NOT_FOUND + break + else throw + + ComCall(IDXGIOutput_GetDesc := 7, IDXGIOutput, "ptr", DXGI_OUTPUT_DESC := Buffer(88+A_PtrSize, 0)) + Width := NumGet(DXGI_OUTPUT_DESC, 72, "int") + Height := NumGet(DXGI_OUTPUT_DESC, 76, "int") + AttachedToDesktop := NumGet(DXGI_OUTPUT_DESC, 80, "int") + if (AttachedToDesktop = 1) + break 2 + } + } + + ; Ensure the desktop is connected. + assert AttachedToDesktop, "No adapter attached to desktop." + + ; Load direct3d + DllCall("D3D11\D3D11CreateDevice" + , "ptr", IDXGIAdapter ; pAdapter + , "int", D3D_DRIVER_TYPE_UNKNOWN := 0 ; DriverType + , "ptr", 0 ; Software + , "uint", 0 ; Flags + , "ptr", 0 ; pFeatureLevels + , "uint", 0 ; FeatureLevels + , "uint", D3D11_SDK_VERSION := 7 ; SDKVersion + , "ptr*", &d3d_device:=0 ; ppDevice + , "ptr*", 0 ; pFeatureLevel + , "ptr*", &d3d_context:=0 ; ppImmediateContext + ,"HRESULT") + + ; Retrieve the desktop duplication API + IDXGIOutput1 := ComObjQuery(IDXGIOutput, "{00cddea8-939b-4b83-a340-a685226666cc}") + ComCall(IDXGIOutput1_DuplicateOutput := 22, IDXGIOutput1, "ptr", d3d_device, "ptr*", &Duplication:=0) + ComCall(IDXGIOutputDuplication_GetDesc := 7, Duplication, "ptr", DXGI_OUTDUPL_DESC := Buffer(36, 0)) + DesktopImageInSystemMemory := NumGet(DXGI_OUTDUPL_DESC, 32, "uint") + Sleep 50 ; As I understand - need some sleep for successful connecting to IDXGIOutputDuplication interface + + ; Create the texture onto which the desktop will be copied to. + D3D11_TEXTURE2D_DESC := Buffer(44, 0) + NumPut("uint", width, D3D11_TEXTURE2D_DESC, 0) ; Width + NumPut("uint", height, D3D11_TEXTURE2D_DESC, 4) ; Height + NumPut("uint", 1, D3D11_TEXTURE2D_DESC, 8) ; MipLevels + NumPut("uint", 1, D3D11_TEXTURE2D_DESC, 12) ; ArraySize + NumPut("uint", DXGI_FORMAT_B8G8R8A8_UNORM := 87, D3D11_TEXTURE2D_DESC, 16) ; Format + NumPut("uint", 1, D3D11_TEXTURE2D_DESC, 20) ; SampleDescCount + NumPut("uint", 0, D3D11_TEXTURE2D_DESC, 24) ; SampleDescQuality + NumPut("uint", D3D11_USAGE_STAGING := 3, D3D11_TEXTURE2D_DESC, 28) ; Usage + NumPut("uint", 0, D3D11_TEXTURE2D_DESC, 32) ; BindFlags + NumPut("uint", D3D11_CPU_ACCESS_READ := 0x20000, D3D11_TEXTURE2D_DESC, 36) ; CPUAccessFlags + NumPut("uint", 0, D3D11_TEXTURE2D_DESC, 40) ; MiscFlags + ComCall(ID3D11Device_CreateTexture2D := 5, d3d_device, "ptr", D3D11_TEXTURE2D_DESC, "ptr", 0, "ptr*", &staging_tex:=0) + + + ; Persist the concept of a desktop_resource as a closure??? + local desktop_resource + + Update(this, timeout := unset) { + ; Unbind resources. + Unbind() + + ; Allocate a shared buffer for all calls of AcquireNextFrame. + static DXGI_OUTDUPL_FRAME_INFO := Buffer(48, 0) + + if !IsSet(timeout) { + ; The following loop structure repeatedly checks for a new frame. + loop { + ; Ask if there is a new frame available immediately. + try ComCall(IDXGIOutputDuplication_AcquireNextFrame := 8, Duplication, "uint", 0, "ptr", DXGI_OUTDUPL_FRAME_INFO, "ptr*", &desktop_resource:=0) + catch OSError as e + if e.number = 0x887A0027 ; DXGI_ERROR_WAIT_TIMEOUT + continue + else throw + + ; Exclude mouse movement events by ensuring LastPresentTime is greater than zero. + if NumGet(DXGI_OUTDUPL_FRAME_INFO, 0, "int64") > 0 + break + + ; Continue the loop by releasing resources. + ObjRelease(desktop_resource) + ComCall(IDXGIOutputDuplication_ReleaseFrame := 14, Duplication) + } + } else { + try ComCall(IDXGIOutputDuplication_AcquireNextFrame := 8, Duplication, "uint", timeout, "ptr", DXGI_OUTDUPL_FRAME_INFO, "ptr*", &desktop_resource:=0) + catch OSError as e + if e.number = 0x887A0027 ; DXGI_ERROR_WAIT_TIMEOUT + return this ; Remember to enable method chaining. + else throw + + if NumGet(DXGI_OUTDUPL_FRAME_INFO, 0, "int64") = 0 + return this ; Remember to enable method chaining. + } + + ; map new resources. + if (DesktopImageInSystemMemory = 1) { + static DXGI_MAPPED_RECT := Buffer(A_PtrSize*2, 0) + ComCall(IDXGIOutputDuplication_MapDesktopSurface := 12, Duplication, "ptr", DXGI_MAPPED_RECT) + pitch := NumGet(DXGI_MAPPED_RECT, 0, "int") + pBits := NumGet(DXGI_MAPPED_RECT, A_PtrSize, "ptr") + } + else { + tex := ComObjQuery(desktop_resource, "{6f15aaf2-d208-4e89-9ab4-489535d34f9c}") ; ID3D11Texture2D + ComCall(ID3D11DeviceContext_CopyResource := 47, d3d_context, "ptr", staging_tex, "ptr", tex) + static D3D11_MAPPED_SUBRESOURCE := Buffer(8+A_PtrSize, 0) + ComCall(ID3D11DeviceContext_Map := 14, d3d_context, "ptr", staging_tex, "uint", 0, "uint", D3D11_MAP_READ := 1, "uint", 0, "ptr", D3D11_MAPPED_SUBRESOURCE) + pBits := NumGet(D3D11_MAPPED_SUBRESOURCE, 0, "ptr") + pitch := NumGet(D3D11_MAPPED_SUBRESOURCE, A_PtrSize, "uint") + } + + this.ptr := pBits + this.size := pitch * height + + ; Remember to enable method chaining. + return this + } + + Unbind() { + if IsSet(desktop_resource) && desktop_resource != 0 { + if (DesktopImageInSystemMemory = 1) + ComCall(IDXGIOutputDuplication_UnMapDesktopSurface := 13, Duplication) + else + ComCall(ID3D11DeviceContext_Unmap := 15, d3d_context, "ptr", staging_tex, "uint", 0) + + ObjRelease(desktop_resource) + ComCall(IDXGIOutputDuplication_ReleaseFrame := 14, Duplication) + } + } + + Cleanup(this) { + Unbind() + ObjRelease(staging_tex) + ObjRelease(duplication) + ObjRelease(d3d_context) + ObjRelease(d3d_device) + IDXGIOutput1 := "" + ObjRelease(IDXGIOutput) + ObjRelease(IDXGIAdapter) + ObjRelease(IDXGIFactory) + } + + ; Get true virtual screen coordinates. + dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") + x := DllCall("GetSystemMetrics", "int", 76, "int") + y := DllCall("GetSystemMetrics", "int", 77, "int") + width := DllCall("GetSystemMetrics", "int", 78, "int") + height := DllCall("GetSystemMetrics", "int", 79, "int") + DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") + + return {x:x, y:y, width: width, + height: height, + Update: Update, + Cleanup : Cleanup}.update() ; init ptr && size. + } + + static from_screenshot2(image) { + obj := this.read_screen() + + width := obj.width + height := obj.height + pBits := obj.ptr + size := obj.size + + ; Create a Bitmap with 32-bit pre-multiplied ARGB. (Owned by this object!) + DllCall("gdiplus\GdipCreateBitmapFromScan0" + , "int", width, "int", height, "uint", size / height, "uint", 0xE200B, "ptr", 0, "ptr*", &pBitmap:=0) + + ; Create a Scan0 buffer pointing to pBits. The buffer has pixel format pARGB. + Rect := Buffer(16, 0) ; sizeof(Rect) = 16 + NumPut( "uint", width, Rect, 8) ; Width + NumPut( "uint", height, Rect, 12) ; Height + BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + NumPut( "int", 4 * width, BitmapData, 8) ; Stride + NumPut( "ptr", pBits, BitmapData, 16) ; Scan0 + + ; Use LockBits to create a writable buffer that converts pARGB to ARGB. + DllCall("gdiplus\GdipBitmapLockBits" + , "ptr", pBitmap + , "ptr", Rect + , "uint", 6 ; ImageLockMode.UserInputBuffer | ImageLockMode.WriteOnly + , "int", 0xE200B ; Format32bppPArgb + , "ptr", BitmapData) ; Contains the pointer (pBits) to the hbm. + + ; Convert the pARGB pixels copied into the device independent bitmap (hbm) to ARGB. + DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", BitmapData) + + return pBitmap + } + static from_screenshot(image) { ; Thanks tic - https://www.autohotkey.com/boards/viewtopic.php?t=6517 From fb16c27f82078b4ccd2c735dc9d1790aca1d6a96 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 27 Jun 2022 10:30:56 -0400 Subject: [PATCH 314/492] Update README.md --- README.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b12ac44f..ba9b3618 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # ImagePut -* Accepts many [inputs](https://github.com/iseahound/ImagePut/wiki/Input-Types-&-Output-Functions#input-types). * Standalone library. -* Easily understandable syntax. -* Fast conversions. +* Easily understandable syntax. +* Accepts all [images](https://github.com/iseahound/ImagePut/wiki/Input-Types-&-Output-Functions#input-types), useful for debugging. +* Fast [pixelsearch](https://github.com/iseahound/ImagePut/wiki/PixelSearch-and-ImageSearch#pixelsearch) and imagesearch. * Highly robust code that has undergone extensive testing. ## Documentation @@ -16,7 +16,7 @@ Projects using ImagePut: -* [PaddleOCR-AutoHotkey](https://github.com/telppa/PaddleOCR-AutoHotkey) +* [PaddleOCR-AutoHotkey](https://github.com/telppa/PaddleOCR-AutoHotkey) - Image to text If you like this and want to see my other AutoHotkey libraries: @@ -78,8 +78,7 @@ Finally, there are several advanced features. The first is the ability to specif ## Help and Support -Come visit the forum for any help, questions, suggestions, etc. +Feel free to ask for any help, questions, or post suggestions, etc. * v1 forum: https://www.autohotkey.com/boards/viewtopic.php?t=76301 * v2 forum: https://www.autohotkey.com/boards/viewtopic.php?t=76633 - From 4cc0882eba94f177f9afd51b57f04cbb4d31ac3b Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 2 Jul 2022 18:59:08 -0400 Subject: [PATCH 315/492] OR operator over NOT AND --- ImagePut (for v1).ahk | 16 ++++++++-------- ImagePut.ahk | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index c6b69231..135498c3 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1711,7 +1711,7 @@ class ImagePut { } __Set(x, y, color) { - (!(color >> 24)) && color |= 0xFF000000 + (color >> 24) || color |= 0xFF000000 NumPut(color, this.ptr + 4*(y*this.width + x), "uint") return color } @@ -1778,7 +1778,7 @@ class ImagePut { ColorKey(key := 0xFFFFFFFF, value := 0x00000000) { ; C source code - https://godbolt.org/z/eaG9fax9v static code := 0 - (!code) && code := this.Base64Put((A_PtrSize == 4) + (code) || code := this.Base64Put((A_PtrSize == 4) ? "VYnli0UIi1UQi00UO0UMcws5EHUCiQiDwATr8F3D" : "SDnRcw5EOQF1A0SJCUiDwQTr7cM=") @@ -1789,7 +1789,7 @@ class ImagePut { SetAlpha(alpha := 0xFF) { ; C source code - https://godbolt.org/z/aWf73jTqc static code := 0 - (!code) && code := this.Base64Put((A_PtrSize == 4) + (code) || code := this.Base64Put((A_PtrSize == 4) ? "VYnli0UIilUQO0UMcwiIUAODwATr813D" : "SDnRcwpEiEEDSIPBBOvxww==") @@ -1800,7 +1800,7 @@ class ImagePut { TransColor(color := 0xFFFFFF, alpha := 0x00) { ; C source code - https://godbolt.org/z/z3a8WcM5M static code := 0 - (!code) && code := this.Base64Put((A_PtrSize == 4) + (code) || code := this.Base64Put((A_PtrSize == 4) ? "VYnli0UIilUUO0UMcxWLTRAzCIHh////AHUDiFADg8AE6+Zdww==" : "SDnRcxaLAUQxwKn///8AdQREiEkDSIPBBOvlww==") @@ -1811,18 +1811,18 @@ class ImagePut { PixelSearch(color, variation := 0) { ; C source code - https://godbolt.org/z/o7EPo8xPr static PixelSearch := 0 - (!PixelSearch) && PixelSearch := this.Base64Put((A_PtrSize == 4) + (PixelSearch) || PixelSearch := this.Base64Put((A_PtrSize == 4) ? "VYnli1UMi00Qi0UIOdBzCTkIdAeDwATr84nQXcM=" : "SInISDnQcwtEOQB0CUiDwATr8EiJ0MM=") ; C source code - https://godbolt.org/z/oocoPndE8 static PixelSearch2 := 0 - (!PixelSearch2) && PixelSearch2 := this.Base64Put((A_PtrSize == 4) + (PixelSearch2) || PixelSearch2 := this.Base64Put((A_PtrSize == 4) ? "VYnlVlNRikUQilUcik0gil0ki3UIiEX3ikUUiEX2ikUYiEX1O3UMcyiKRgI6Rfd3GzpF9nIWikYBOkX1dw440HIKigY4yHcEONhzCIPGBOvTi3UMWonwW15dww==" : "VlNEilQkOESKXCRAilwkSECKdCRQSInISDnQcyuKSAJEOMF3HUQ4yXIYikgBRDjRdxBEONlyC4oIONl3BUA48XMJSIPABOvQSInQW17D") ; Lift color to 32-bits if first 8 bits are zero. - (!(color >> 24)) && color |= 0xFF000000 + (color >> 24) || color |= 0xFF000000 ; PixelSearch, no variation, no range if (variation <= 0) { @@ -1869,7 +1869,7 @@ class ImagePut { ImageSearch(image) { ; C source code - https://godbolt.org/z/q1rxvx38Y static code := 0 - (!code) && code := this.Base64Put((A_PtrSize == 4) + (code) || code := this.Base64Put((A_PtrSize == 4) ? "VYnlV1ZTg+wUi1UYi3UUi0UQi30MjTSWi00MiXXoi3UcjRyFAAAAACnXK0UcD6/LA00IiX3kweYCiUXgiXXsiU3wi00IO03wc0yL" . "RRSLADkBdT6JyCtFCDHSwfgC93UMOVXkfiw5ReB+J4tFFInKMf87fRx0IztF6HMOizI5MHUQg8IEg8AE6+0B2gNF7Efr4IPBBOuv" . "i03wg8QUichbXl9dww==" diff --git a/ImagePut.ahk b/ImagePut.ahk index 8b90dfbd..e5478da3 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1923,7 +1923,7 @@ class ImagePut { __Item[x, y] { get => Format("0x{:X}", NumGet(this.ptr + 4*(y*this.width + x), "uint")) - set => ((!(value >> 24)) && value |= 0xFF000000, + set => ((value >> 24) || value |= 0xFF000000, NumPut("uint", value, this.ptr + 4*(y*this.width + x)), value) } @@ -1993,7 +1993,7 @@ class ImagePut { ColorKey(key := 0xFFFFFFFF, value := 0x00000000) { ; C source code - https://godbolt.org/z/eaG9fax9v static code := 0 - (!code) && code := this.Base64Put((A_PtrSize == 4) + (code) || code := this.Base64Put((A_PtrSize == 4) ? "VYnli0UIi1UQi00UO0UMcws5EHUCiQiDwATr8F3D" : "SDnRcw5EOQF1A0SJCUiDwQTr7cM=") @@ -2004,7 +2004,7 @@ class ImagePut { SetAlpha(alpha := 0xFF) { ; C source code - https://godbolt.org/z/aWf73jTqc static code := 0 - (!code) && code := this.Base64Put((A_PtrSize == 4) + (code) || code := this.Base64Put((A_PtrSize == 4) ? "VYnli0UIilUQO0UMcwiIUAODwATr813D" : "SDnRcwpEiEEDSIPBBOvxww==") @@ -2015,7 +2015,7 @@ class ImagePut { TransColor(color := 0xFFFFFF, alpha := 0x00) { ; C source code - https://godbolt.org/z/z3a8WcM5M static code := 0 - (!code) && code := this.Base64Put((A_PtrSize == 4) + (code) || code := this.Base64Put((A_PtrSize == 4) ? "VYnli0UIilUUO0UMcxWLTRAzCIHh////AHUDiFADg8AE6+Zdww==" : "SDnRcxaLAUQxwKn///8AdQREiEkDSIPBBOvlww==") @@ -2026,18 +2026,18 @@ class ImagePut { PixelSearch(color, variation := 0) { ; C source code - https://godbolt.org/z/o7EPo8xPr static PixelSearch := 0 - (!PixelSearch) && PixelSearch := this.Base64Put((A_PtrSize == 4) + (PixelSearch) || PixelSearch := this.Base64Put((A_PtrSize == 4) ? "VYnli1UMi00Qi0UIOdBzCTkIdAeDwATr84nQXcM=" : "SInISDnQcwtEOQB0CUiDwATr8EiJ0MM=") ; C source code - https://godbolt.org/z/oocoPndE8 static PixelSearch2 := 0 - (!PixelSearch2) && PixelSearch2 := this.Base64Put((A_PtrSize == 4) + (PixelSearch2) || PixelSearch2 := this.Base64Put((A_PtrSize == 4) ? "VYnlVlNRikUQilUcik0gil0ki3UIiEX3ikUUiEX2ikUYiEX1O3UMcyiKRgI6Rfd3GzpF9nIWikYBOkX1dw440HIKigY4yHcEONhzCIPGBOvTi3UMWonwW15dww==" : "VlNEilQkOESKXCRAilwkSECKdCRQSInISDnQcyuKSAJEOMF3HUQ4yXIYikgBRDjRdxBEONlyC4oIONl3BUA48XMJSIPABOvQSInQW17D") ; Lift color to 32-bits if first 8 bits are zero. - (!(color >> 24)) && color |= 0xFF000000 + (color >> 24) || color |= 0xFF000000 ; PixelSearch, no variation, no range if (variation <= 0) { @@ -2084,7 +2084,7 @@ class ImagePut { ImageSearch(image) { ; C source code - https://godbolt.org/z/q1rxvx38Y static code := 0 - (!code) && code := this.Base64Put((A_PtrSize == 4) + (code) || code := this.Base64Put((A_PtrSize == 4) ? "VYnlV1ZTg+wUi1UYi3UUi0UQi30MjTSWi00MiXXoi3UcjRyFAAAAACnXK0UcD6/LA00IiX3kweYCiUXgiXXsiU3wi00IO03wc0yL" . "RRSLADkBdT6JyCtFCDHSwfgC93UMOVXkfiw5ReB+J4tFFInKMf87fRx0IztF6HMOizI5MHUQg8IEg8AE6+0B2gNF7Efr4IPBBOuv" . "i03wg8QUichbXl9dww==" From 8f00146de573f2877996466f6a0cd92109897bfe Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 3 Jul 2022 00:05:17 -0400 Subject: [PATCH 316/492] Allow set decode & validate to override globals --- ImagePut (for v1).ahk | 4 ++-- ImagePut.ahk | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 135498c3..a27adcb7 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -169,8 +169,8 @@ class ImagePut { crop := keywords.crop scale := keywords.scale - decode := keywords.decode ? keywords.decode : this.decode - validate := keywords.validate ? keywords.validate : this.validate + decode := (keywords.decode != "") ? keywords.decode : this.decode + validate := (keywords.validate != "") ? keywords.validate : this.validate ; #1 - Stream intermediate. if not decode and not crop and not scale diff --git a/ImagePut.ahk b/ImagePut.ahk index e5478da3..fcb1e689 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -169,8 +169,8 @@ class ImagePut { crop := keywords.crop scale := keywords.scale - decode := keywords.decode ? keywords.decode : this.decode - validate := keywords.validate ? keywords.validate : this.validate + decode := (keywords.decode != "") ? keywords.decode : this.decode + validate := (keywords.validate != "") ? keywords.validate : this.validate ; #1 - Stream intermediate. if not decode and not crop and not scale From 226bc19bd9193c2ac3189ca97ebd41bd559ce95e Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 16 Jul 2022 20:50:49 -0400 Subject: [PATCH 317/492] C source files --- source/imagesearch.c | 2 +- source/pixelsearch.c | 2 +- source/pixelsearch2.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/source/imagesearch.c b/source/imagesearch.c index 4ce00c8a..24d7f51c 100644 --- a/source/imagesearch.c +++ b/source/imagesearch.c @@ -42,5 +42,5 @@ unsigned int * imagesearch(unsigned int * Scan0, unsigned int width, unsigned in next: start++; } - return end; + return start; // start == end if no match. } \ No newline at end of file diff --git a/source/pixelsearch.c b/source/pixelsearch.c index 72043d0b..c95d2ad6 100644 --- a/source/pixelsearch.c +++ b/source/pixelsearch.c @@ -4,5 +4,5 @@ unsigned int * pixelsearch(unsigned int * start, unsigned int * end, unsigned in return start; start++; } - return end; + return start; // start == end if no match. } \ No newline at end of file diff --git a/source/pixelsearch2.c b/source/pixelsearch2.c index cb2cdd4f..1fbea41b 100644 --- a/source/pixelsearch2.c +++ b/source/pixelsearch2.c @@ -8,5 +8,5 @@ unsigned int * pixelsearch2(unsigned int * start, unsigned int * end, unsigned c return start; start++; } - return end; + return start; // start == end if no match. } \ No newline at end of file From 9b6cbb5e858ce4340ea69de6a423d691de02413e Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 21 Jul 2022 22:26:06 -0400 Subject: [PATCH 318/492] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ba9b3618..6e433fc2 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ ## Documentation +* [Quick Start](https://github.com/iseahound/ImagePut/wiki/Quick-Start) * [Input Types & Output Functions](https://github.com/iseahound/ImagePut/wiki/Input-Types-&-Output-Functions) * [Crop, Scale, & Other Flags](https://github.com/iseahound/ImagePut/wiki/Crop,-Scale,-&-Other-Flags) * [PixelSearch & ImageSearch](https://github.com/iseahound/ImagePut/wiki/PixelSearch-and-ImageSearch) From 5873a16fcc232173058fa42d1bbf4da1a16b6c8d Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 21 Jul 2022 22:36:21 -0400 Subject: [PATCH 319/492] Update README.md --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index 6e433fc2..2a98bf16 100644 --- a/README.md +++ b/README.md @@ -19,10 +19,6 @@ Projects using ImagePut: * [PaddleOCR-AutoHotkey](https://github.com/telppa/PaddleOCR-AutoHotkey) - Image to text -If you like this and want to see my other AutoHotkey libraries: - -* [TextRender & ImageRender](https://github.com/iseahound/TextRender) - ## So you want to convert an image? But you don't know how. That's okay because you can just do this: From 67670491e76a9ee64b54d84612f2b9a414fedc0a Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 21 Jul 2022 22:37:31 -0400 Subject: [PATCH 320/492] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2a98bf16..e502672a 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ * Chinese Documentation (中文) - [这里有一个中文版的使用教程](https://www.autoahk.com/archives/37246) * [Engineering Challenges Q&A](https://github.com/iseahound/ImagePut/wiki/Engineering-Challenges-Q&A) - Click here to read some interesting stuff. -Projects using ImagePut: +Completed Projects: * [PaddleOCR-AutoHotkey](https://github.com/telppa/PaddleOCR-AutoHotkey) - Image to text From d631e86a34c169ec16eefbbbb009dbea4eb89893 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 22 Jul 2022 22:23:24 -0400 Subject: [PATCH 321/492] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e502672a..6df32ab0 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ * Chinese Documentation (中文) - [这里有一个中文版的使用教程](https://www.autoahk.com/archives/37246) * [Engineering Challenges Q&A](https://github.com/iseahound/ImagePut/wiki/Engineering-Challenges-Q&A) - Click here to read some interesting stuff. -Completed Projects: +Used by: * [PaddleOCR-AutoHotkey](https://github.com/telppa/PaddleOCR-AutoHotkey) - Image to text From b139d8b18763b60e5dd46b83b73ab70db4749cee Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 22 Jul 2022 22:23:49 -0400 Subject: [PATCH 322/492] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6df32ab0..fb5361b5 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ * Chinese Documentation (中文) - [这里有一个中文版的使用教程](https://www.autoahk.com/archives/37246) * [Engineering Challenges Q&A](https://github.com/iseahound/ImagePut/wiki/Engineering-Challenges-Q&A) - Click here to read some interesting stuff. -Used by: +Check out these projects using ImagePut: * [PaddleOCR-AutoHotkey](https://github.com/telppa/PaddleOCR-AutoHotkey) - Image to text From 8404c9d2c7a15b05fc3cf6fad60f204306f15a3c Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 22 Jul 2022 22:24:13 -0400 Subject: [PATCH 323/492] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fb5361b5..3c187dac 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ * Chinese Documentation (中文) - [这里有一个中文版的使用教程](https://www.autoahk.com/archives/37246) * [Engineering Challenges Q&A](https://github.com/iseahound/ImagePut/wiki/Engineering-Challenges-Q&A) - Click here to read some interesting stuff. -Check out these projects using ImagePut: +Sample Projects: * [PaddleOCR-AutoHotkey](https://github.com/telppa/PaddleOCR-AutoHotkey) - Image to text From a0fa2c86db26eb327d1f3509bcd02293fc89c1a5 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 22 Jul 2022 22:40:56 -0400 Subject: [PATCH 324/492] Rename ImageTypes to inputs --- ImagePut (for v1).ahk | 4 ++-- ImagePut.ahk | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index a27adcb7..b7017ca2 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -220,7 +220,7 @@ class ImagePut { return ObjHasKey(this, name) ? this.name : "" } - static ImageTypes := + static inputs := ( Join [ "clipboard_png", @@ -268,7 +268,7 @@ class ImagePut { } ; Skip ImageType. - for i, type in this.ImageTypes + for i, type in this.inputs if ObjHasKey(image, type) { keywords := image keywords.base := {__get: this.get} diff --git a/ImagePut.ahk b/ImagePut.ahk index fcb1e689..573cdc27 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -220,7 +220,7 @@ class ImagePut { return ObjHasOwnProp(this, name) ? this.name : "" } - static ImageTypes := [ + static inputs := [ "clipboard_png", "clipboard", "object", @@ -268,7 +268,7 @@ class ImagePut { } ; Skip ImageType. - for type in this.ImageTypes + for type in this.inputs if ObjHasOwnProp(image, type) { keywords := image keywords.base := {__get: this.get} From 53f8b947f6c6217b113931a13eafc59ca3425439 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 22 Jul 2022 23:45:02 -0400 Subject: [PATCH 325/492] Allow a range of colors to be specified through variation --- ImagePut (for v1).ahk | 41 ++++++++++++++++++++++------------------- ImagePut.ahk | 41 ++++++++++++++++++++++------------------- 2 files changed, 44 insertions(+), 38 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index b7017ca2..754745b7 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1824,24 +1824,27 @@ class ImagePut { ; Lift color to 32-bits if first 8 bits are zero. (color >> 24) || color |= 0xFF000000 - ; PixelSearch, no variation, no range - if (variation <= 0) { + ; PixelSearch, range of colors, and variation. + if IsObject(variation) { + byte := DllCall(PixelSearch2, "ptr", this.ptr, "ptr", this.ptr + this.size + , "uchar", variation[1] + , "uchar", variation[2] + , "uchar", variation[3] + , "uchar", variation[4] + , "uchar", variation[5] + , "uchar", variation[6] + , "ptr") + } + ; PixelSearch, single color, no variation + else if (variation == 0) { ; Get the address of the first matching pixel. byte := DllCall(PixelSearch, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "ptr") - - ; Compare the address to the out-of-bounds limit. - if (byte == this.ptr + this.size) - return False - - ; Return an [x, y] array. - offset := (byte - this.ptr) // 4 - return [mod(offset, this.width), offset // this.width] } - ; PixelSearch with variation + ; PixelSearch, single color, and variation else { - v := variation + v := abs(variation) r := ((color & 0xFF0000) >> 16) g := ((color & 0xFF00) >> 8) b := ((color & 0xFF)) @@ -1855,15 +1858,15 @@ class ImagePut { , "uchar", Min(b+v, 255) , "uchar", Max(b-v, 0) , "ptr") + } - ; Compare the address to the out-of-bounds limit. - if (byte == this.ptr + this.size) - return False + ; Compare the address to the out-of-bounds limit. + if (byte == this.ptr + this.size) + return False - ; Return an [x, y] array. - offset := (byte - this.ptr) // 4 - return [mod(offset, this.width), offset // this.width] - } + ; Return an [x, y] array. + offset := (byte - this.ptr) // 4 + return [mod(offset, this.width), offset // this.width] } ImageSearch(image) { diff --git a/ImagePut.ahk b/ImagePut.ahk index 573cdc27..2bb260b4 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2039,24 +2039,27 @@ class ImagePut { ; Lift color to 32-bits if first 8 bits are zero. (color >> 24) || color |= 0xFF000000 - ; PixelSearch, no variation, no range - if (variation <= 0) { + ; PixelSearch, range of colors, and variation. + if IsObject(variation) { + byte := DllCall(PixelSearch2, "ptr", this.ptr, "ptr", this.ptr + this.size + , "uchar", variation[1] + , "uchar", variation[2] + , "uchar", variation[3] + , "uchar", variation[4] + , "uchar", variation[5] + , "uchar", variation[6] + , "ptr") + } + ; PixelSearch, single color, no variation + else if (variation == 0) { ; Get the address of the first matching pixel. byte := DllCall(PixelSearch, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "ptr") - - ; Compare the address to the out-of-bounds limit. - if (byte == this.ptr + this.size) - return False - - ; Return an [x, y] array. - offset := (byte - this.ptr) // 4 - return [mod(offset, this.width), offset // this.width] } - ; PixelSearch with variation + ; PixelSearch, single color, and variation else { - v := variation + v := abs(variation) r := ((color & 0xFF0000) >> 16) g := ((color & 0xFF00) >> 8) b := ((color & 0xFF)) @@ -2070,15 +2073,15 @@ class ImagePut { , "uchar", Min(b+v, 255) , "uchar", Max(b-v, 0) , "ptr") + } - ; Compare the address to the out-of-bounds limit. - if (byte == this.ptr + this.size) - return False + ; Compare the address to the out-of-bounds limit. + if (byte == this.ptr + this.size) + return False - ; Return an [x, y] array. - offset := (byte - this.ptr) // 4 - return [mod(offset, this.width), offset // this.width] - } + ; Return an [x, y] array. + offset := (byte - this.ptr) // 4 + return [mod(offset, this.width), offset // this.width] } ImageSearch(image) { From edd77a3e252de48fe12249f90ecc3368e899dc02 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 23 Jul 2022 00:03:16 -0400 Subject: [PATCH 326/492] =?UTF-8?q?Color=20channels=20can=20be=20low=20?= =?UTF-8?q?=E2=86=92=20high=20OR=20high=20=E2=86=92=20low?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ImagePut (for v1).ahk | 12 ++++++------ ImagePut.ahk | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 754745b7..2a128f5b 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1827,12 +1827,12 @@ class ImagePut { ; PixelSearch, range of colors, and variation. if IsObject(variation) { byte := DllCall(PixelSearch2, "ptr", this.ptr, "ptr", this.ptr + this.size - , "uchar", variation[1] - , "uchar", variation[2] - , "uchar", variation[3] - , "uchar", variation[4] - , "uchar", variation[5] - , "uchar", variation[6] + , "uchar", Max(variation[1], variation[2]) + , "uchar", Min(variation[1], variation[2]) + , "uchar", Max(variation[3], variation[4]) + , "uchar", Min(variation[3], variation[4]) + , "uchar", Max(variation[5], variation[6]) + , "uchar", Min(variation[5], variation[6]) , "ptr") } diff --git a/ImagePut.ahk b/ImagePut.ahk index 2bb260b4..24ab008f 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2042,12 +2042,12 @@ class ImagePut { ; PixelSearch, range of colors, and variation. if IsObject(variation) { byte := DllCall(PixelSearch2, "ptr", this.ptr, "ptr", this.ptr + this.size - , "uchar", variation[1] - , "uchar", variation[2] - , "uchar", variation[3] - , "uchar", variation[4] - , "uchar", variation[5] - , "uchar", variation[6] + , "uchar", Max(variation[1], variation[2]) + , "uchar", Min(variation[1], variation[2]) + , "uchar", Max(variation[3], variation[4]) + , "uchar", Min(variation[3], variation[4]) + , "uchar", Max(variation[5], variation[6]) + , "uchar", Min(variation[5], variation[6]) , "ptr") } From a75d5af81bae488d93a4b9b62583b769d9f18151 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 23 Jul 2022 08:45:58 -0400 Subject: [PATCH 327/492] lowercase Min and Max --- ImagePut (for v1).ahk | 26 +++++++++++++------------- ImagePut.ahk | 26 +++++++++++++------------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 2a128f5b..33b00208 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1827,12 +1827,12 @@ class ImagePut { ; PixelSearch, range of colors, and variation. if IsObject(variation) { byte := DllCall(PixelSearch2, "ptr", this.ptr, "ptr", this.ptr + this.size - , "uchar", Max(variation[1], variation[2]) - , "uchar", Min(variation[1], variation[2]) - , "uchar", Max(variation[3], variation[4]) - , "uchar", Min(variation[3], variation[4]) - , "uchar", Max(variation[5], variation[6]) - , "uchar", Min(variation[5], variation[6]) + , "uchar", max(variation[1], variation[2]) + , "uchar", min(variation[1], variation[2]) + , "uchar", max(variation[3], variation[4]) + , "uchar", min(variation[3], variation[4]) + , "uchar", max(variation[5], variation[6]) + , "uchar", min(variation[5], variation[6]) , "ptr") } @@ -1851,12 +1851,12 @@ class ImagePut { ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. byte := DllCall(PixelSearch2, "ptr", this.ptr, "ptr", this.ptr + this.size - , "uchar", Min(r+v, 255) - , "uchar", Max(r-v, 0) - , "uchar", Min(g+v, 255) - , "uchar", Max(g-v, 0) - , "uchar", Min(b+v, 255) - , "uchar", Max(b-v, 0) + , "uchar", min(r+v, 255) + , "uchar", max(r-v, 0) + , "uchar", min(g+v, 255) + , "uchar", max(g-v, 0) + , "uchar", min(b+v, 255) + , "uchar", max(b-v, 0) , "ptr") } @@ -2298,7 +2298,7 @@ class ImagePut { frames := NumGet(Item+0, 4, "uint") // 4 ; Max frames delays := NumGet(Item+0, 8 + A_PtrSize, "ptr") ; Array of delays frame := mod(frame, frames) ; Loop to first frame - delay := Max(10 * NumGet(delays+0, frame*4, "uint"), 10) ; Minimum delay is 10ms + delay := max(10 * NumGet(delays+0, frame*4, "uint"), 10) ; Minimum delay is 10ms ; Emulate behavior of setting 10 ms to 100 ms. (delay == 10) && delay := 100 ; See: https://www.biphelps.com/blog/The-Fastest-GIF-Does-Not-Exist diff --git a/ImagePut.ahk b/ImagePut.ahk index 24ab008f..2a32c08c 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2042,12 +2042,12 @@ class ImagePut { ; PixelSearch, range of colors, and variation. if IsObject(variation) { byte := DllCall(PixelSearch2, "ptr", this.ptr, "ptr", this.ptr + this.size - , "uchar", Max(variation[1], variation[2]) - , "uchar", Min(variation[1], variation[2]) - , "uchar", Max(variation[3], variation[4]) - , "uchar", Min(variation[3], variation[4]) - , "uchar", Max(variation[5], variation[6]) - , "uchar", Min(variation[5], variation[6]) + , "uchar", max(variation[1], variation[2]) + , "uchar", min(variation[1], variation[2]) + , "uchar", max(variation[3], variation[4]) + , "uchar", min(variation[3], variation[4]) + , "uchar", max(variation[5], variation[6]) + , "uchar", min(variation[5], variation[6]) , "ptr") } @@ -2066,12 +2066,12 @@ class ImagePut { ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. byte := DllCall(PixelSearch2, "ptr", this.ptr, "ptr", this.ptr + this.size - , "uchar", Min(r+v, 255) - , "uchar", Max(r-v, 0) - , "uchar", Min(g+v, 255) - , "uchar", Max(g-v, 0) - , "uchar", Min(b+v, 255) - , "uchar", Max(b-v, 0) + , "uchar", min(r+v, 255) + , "uchar", max(r-v, 0) + , "uchar", min(g+v, 255) + , "uchar", max(g-v, 0) + , "uchar", min(b+v, 255) + , "uchar", max(b-v, 0) , "ptr") } @@ -2513,7 +2513,7 @@ class ImagePut { frames := NumGet(Item, 4, "uint") // 4 ; Max frames delays := NumGet(Item, 8 + A_PtrSize, "ptr") ; Array of delays frame := mod(frame, frames) ; Loop to first frame - delay := Max(10 * NumGet(delays, frame*4, "uint"), 10) ; Minimum delay is 10ms + delay := max(10 * NumGet(delays, frame*4, "uint"), 10) ; Minimum delay is 10ms ; Emulate behavior of setting 10 ms to 100 ms. (delay == 10) && delay := 100 ; See: https://www.biphelps.com/blog/The-Fastest-GIF-Does-Not-Exist From 2af8a28e67fe1165a5ac56a41f52c9e130837cc9 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 23 Jul 2022 08:48:00 -0400 Subject: [PATCH 328/492] Bound variation channels to [0-255] --- ImagePut (for v1).ahk | 12 ++++++------ ImagePut.ahk | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 33b00208..04af999f 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1827,12 +1827,12 @@ class ImagePut { ; PixelSearch, range of colors, and variation. if IsObject(variation) { byte := DllCall(PixelSearch2, "ptr", this.ptr, "ptr", this.ptr + this.size - , "uchar", max(variation[1], variation[2]) - , "uchar", min(variation[1], variation[2]) - , "uchar", max(variation[3], variation[4]) - , "uchar", min(variation[3], variation[4]) - , "uchar", max(variation[5], variation[6]) - , "uchar", min(variation[5], variation[6]) + , "uchar", min(max(variation[1], variation[2]), 255) + , "uchar", max(min(variation[1], variation[2]), 0) + , "uchar", min(max(variation[3], variation[4]), 255) + , "uchar", max(min(variation[3], variation[4]), 0) + , "uchar", min(max(variation[5], variation[6]), 255) + , "uchar", max(min(variation[5], variation[6]), 0) , "ptr") } diff --git a/ImagePut.ahk b/ImagePut.ahk index 2a32c08c..387d0305 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2042,12 +2042,12 @@ class ImagePut { ; PixelSearch, range of colors, and variation. if IsObject(variation) { byte := DllCall(PixelSearch2, "ptr", this.ptr, "ptr", this.ptr + this.size - , "uchar", max(variation[1], variation[2]) - , "uchar", min(variation[1], variation[2]) - , "uchar", max(variation[3], variation[4]) - , "uchar", min(variation[3], variation[4]) - , "uchar", max(variation[5], variation[6]) - , "uchar", min(variation[5], variation[6]) + , "uchar", min(max(variation[1], variation[2]), 255) + , "uchar", max(min(variation[1], variation[2]), 0) + , "uchar", min(max(variation[3], variation[4]), 255) + , "uchar", max(min(variation[3], variation[4]), 0) + , "uchar", min(max(variation[5], variation[6]), 255) + , "uchar", max(min(variation[5], variation[6]), 0) , "ptr") } From daa83879b43c5028dccc90e17e41dbc8184150dd Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 23 Jul 2022 08:58:47 -0400 Subject: [PATCH 329/492] Shorten pixelsearch2 assembly by one instruction --- ImagePut (for v1).ahk | 6 +++--- ImagePut.ahk | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 04af999f..7a43bb8e 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1815,11 +1815,11 @@ class ImagePut { ? "VYnli1UMi00Qi0UIOdBzCTkIdAeDwATr84nQXcM=" : "SInISDnQcwtEOQB0CUiDwATr8EiJ0MM=") - ; C source code - https://godbolt.org/z/oocoPndE8 + ; C source code - https://godbolt.org/z/4K38sq8hY static PixelSearch2 := 0 (PixelSearch2) || PixelSearch2 := this.Base64Put((A_PtrSize == 4) - ? "VYnlVlNRikUQilUcik0gil0ki3UIiEX3ikUUiEX2ikUYiEX1O3UMcyiKRgI6Rfd3GzpF9nIWikYBOkX1dw440HIKigY4yHcEONhzCIPGBOvTi3UMWonwW15dww==" - : "VlNEilQkOESKXCRAilwkSECKdCRQSInISDnQcyuKSAJEOMF3HUQ4yXIYikgBRDjRdxBEONlyC4oIONl3BUA48XMJSIPABOvQSInQW17D") + ? "VYnlVlNRikUQilUcik0gil0ki3UIiEX3ikUUiEX2ikUYiEX1O3UMcyiKRgI4RfdyGzpF9nIWikYBOEX1cg440HIKigY4wXIEONhzBYPGBOvTWonwW15dww==" + : "VlNEilQkOESKXCRAilwkSECKdCRQSInISDnQcyuKSAJBOMhyHUQ4yXIYikgBQTjKchBEONlyC4oIOMtyBUA48XMGSIPABOvQW17D") ; Lift color to 32-bits if first 8 bits are zero. (color >> 24) || color |= 0xFF000000 diff --git a/ImagePut.ahk b/ImagePut.ahk index 387d0305..f6e28e95 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2030,11 +2030,11 @@ class ImagePut { ? "VYnli1UMi00Qi0UIOdBzCTkIdAeDwATr84nQXcM=" : "SInISDnQcwtEOQB0CUiDwATr8EiJ0MM=") - ; C source code - https://godbolt.org/z/oocoPndE8 + ; C source code - https://godbolt.org/z/4K38sq8hY static PixelSearch2 := 0 (PixelSearch2) || PixelSearch2 := this.Base64Put((A_PtrSize == 4) - ? "VYnlVlNRikUQilUcik0gil0ki3UIiEX3ikUUiEX2ikUYiEX1O3UMcyiKRgI6Rfd3GzpF9nIWikYBOkX1dw440HIKigY4yHcEONhzCIPGBOvTi3UMWonwW15dww==" - : "VlNEilQkOESKXCRAilwkSECKdCRQSInISDnQcyuKSAJEOMF3HUQ4yXIYikgBRDjRdxBEONlyC4oIONl3BUA48XMJSIPABOvQSInQW17D") + ? "VYnlVlNRikUQilUcik0gil0ki3UIiEX3ikUUiEX2ikUYiEX1O3UMcyiKRgI4RfdyGzpF9nIWikYBOEX1cg440HIKigY4wXIEONhzBYPGBOvTWonwW15dww==" + : "VlNEilQkOESKXCRAilwkSECKdCRQSInISDnQcyuKSAJBOMhyHUQ4yXIYikgBQTjKchBEONlyC4oIOMtyBUA48XMGSIPABOvQW17D") ; Lift color to 32-bits if first 8 bits are zero. (color >> 24) || color |= 0xFF000000 From 4678f2d8526f5a37505116e0bd03b58955b6d61c Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 24 Jul 2022 18:42:31 -0400 Subject: [PATCH 330/492] =?UTF-8?q?Standardize=20base64=20=E2=86=92=20asse?= =?UTF-8?q?mbly=20code=20names?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ImagePut (for v1).ahk | 70 ++++++++++++++++++++--------------------- ImagePut.ahk | 73 +++++++++++++++++++++---------------------- 2 files changed, 71 insertions(+), 72 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 7a43bb8e..5ef708fa 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1533,20 +1533,20 @@ class ImagePut { , "ptr", &BitmapData) Scan0 := NumGet(BitmapData, 16, "ptr") - ; Generate machine code. - static bin := 0 - if !bin { - ; C source code - https://godbolt.org/z/rvTWqrqv6 - code := (A_PtrSize == 4) - ? "VYnli0UIi1UMi00QjRSQOdBzDzkIdQbHAAAAAACDwATr7V3D" - : "idJIjQSRSDnBcxFEOQF1BscBAAAAAEiDwQTr6sM=" - size := StrLen(RTrim(code, "=")) * 3 // 4 - bin := DllCall("VirtualAlloc", "ptr", 0, "uptr", size, "uint", 0x00003000, "uint", 0x40) - DllCall("crypt32\CryptStringToBinary", "str", code, "uint", 0, "uint", 0x1, "ptr", bin, "uint*", size, "ptr", 0, "ptr", 0) + ; C source code - https://godbolt.org/z/nrv5Yr3Y3 + static code := 0 + if !code { + b64 := (A_PtrSize == 4) + ? "VYnli0UIi1UMi00QOdBzDzkIdQbHAAAAAACDwATr7V3D" + : "SDnRcw9EOQF1BDHAiQFIg8EE6+zD" + s64 := StrLen(RTrim(b64, "=")) * 3 // 4 + code := DllCall("GlobalAlloc", "uint", 0, "uptr", s64, "ptr") + DllCall("crypt32\CryptStringToBinary", "str", b64, "uint", 0, "uint", 0x1, "ptr", code, "uint*", s64, "ptr", 0, "ptr", 0) + DllCall("VirtualProtect", "ptr", code, "ptr", s64, "uint", 0x40, "uint*", op:=0) } - ; Call colorkey. - DllCall(bin, "ptr", Scan0, "uint", width * height, "uint", NumGet(Scan0+0, "uint")) + ; Sample the top-left pixel and set all matching pixels to be transparent. + DllCall(code, "ptr", Scan0, "ptr", Scan0 + 4*width*height, "uint", NumGet(Scan0+0, "uint")) ; Write pixels to bitmap. DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", &BitmapData) @@ -1728,12 +1728,12 @@ class ImagePut { : ImagePut.show(this.pBitmap, title, pos, style, styleEx, parent) } - Base64Put(code) { - size := StrLen(RTrim(code, "=")) * 3 // 4 - bin := DllCall("GlobalAlloc", "uint", 0, "uptr", size, "ptr") - DllCall("VirtualProtect", "ptr", bin, "ptr", size, "uint", 0x40, "uint*", old:=0) - DllCall("crypt32\CryptStringToBinary", "str", code, "uint", 0, "uint", 0x1, "ptr", bin, "uint*", size, "ptr", 0, "ptr", 0) - return bin + Base64Put(b64) { + s64 := StrLen(RTrim(b64, "=")) * 3 // 4 + code := DllCall("GlobalAlloc", "uint", 0, "uptr", s64, "ptr") + DllCall("crypt32\CryptStringToBinary", "str", b64, "uint", 0, "uint", 0x1, "ptr", code, "uint*", s64, "ptr", 0, "ptr", 0) + DllCall("VirtualProtect", "ptr", code, "ptr", s64, "uint", 0x40, "uint*", op:=0) + return code } CPUID() { @@ -1741,21 +1741,21 @@ class ImagePut { if not cpuid { ; C source code - https://godbolt.org/z/1YPd6jz61 - code := (A_PtrSize == 4) + b64 := (A_PtrSize == 4) ? "VYnlV4t9EFaLdQhTiw+LBg+iiQaLRQyJGItFFIkPiRBbXl9dww==" : "U4sBSYnKSYnTQYsID6JBiQJBiRtBiQhBiRFbww==" - size := StrLen(RTrim(code, "=")) * 3 // 4 - bin := DllCall("GlobalAlloc", "uint", 0, "uptr", size, "ptr") - DllCall("VirtualProtect", "ptr", bin, "ptr", size, "uint", 0x40, "uint*", old:=0) - DllCall("crypt32\CryptStringToBinary", "str", code, "uint", 0, "uint", 0x1, "ptr", bin, "uint*", size, "ptr", 0, "ptr", 0) + s64 := StrLen(RTrim(b64, "=")) * 3 // 4 + code := DllCall("GlobalAlloc", "uint", 0, "uptr", s64, "ptr") + DllCall("crypt32\CryptStringToBinary", "str", b64, "uint", 0, "uint", 0x1, "ptr", code, "uint*", s64, "ptr", 0, "ptr", 0) + DllCall("VirtualProtect", "ptr", code, "ptr", s64, "uint", 0x40, "uint*", op:=0) ; Set eax flag to 1 to retrieve supported CPU features. ; See this for CPU features: https://wiki.osdev.org/CPUID ; Also see page 591: https://www.amd.com/system/files/TechDocs/24594.pdf - DllCall(bin, "uint*", a := 1, "uint*", b := 0, "uint*", c := 0, "uint*", d := 0) + DllCall(code, "uint*", a := 1, "uint*", b := 0, "uint*", c := 0, "uint*", d := 0) ; Free memory. - DllCall("GlobalFree", "ptr", bin) + DllCall("GlobalFree", "ptr", code) ; To check for SSE2 use the following code example: ; if cpuid().edx[26] == True @@ -2559,13 +2559,13 @@ class ImagePut { ; C source code - https://godbolt.org/z/EqfK7fvr5 static code := 0 if !code { - code_str := (A_PtrSize == 4) + b64 := (A_PtrSize == 4) ? "VYnlVotFDIt1EFOLTRSLXQgBxjnwcyCKEIPBAkDA6gQPttKKFBOIUf6KUP+D4g+KFBOIUf/r3FteXcM=" : "SQHQTDnCcyWKAkmDwQJI/8LA6AQPtsCKBAFBiEH+ikL/g+APigQBQYhB/+vWww==" - code_size := StrLen(RTrim(code_str, "=")) * 3 // 4 - code := DllCall("GlobalAlloc", "uint", 0, "uptr", code_size, "ptr") - DllCall("VirtualProtect", "ptr", code, "ptr", code_size, "uint", 0x40, "uint*", code_old:=0) - DllCall("crypt32\CryptStringToBinary", "str", code_str, "uint", 0, "uint", 0x1, "ptr", code, "uint*", code_size, "ptr", 0, "ptr", 0) + s64 := StrLen(RTrim(b64, "=")) * 3 // 4 + code := DllCall("GlobalAlloc", "uint", 0, "uptr", s64, "ptr") + DllCall("crypt32\CryptStringToBinary", "str", b64, "uint", 0, "uint", 0x1, "ptr", code, "uint*", s64, "ptr", 0, "ptr", 0) + DllCall("VirtualProtect", "ptr", code, "ptr", s64, "uint", 0x40, "uint*", op:=0) } ; Default to lowercase hex values. Or capitalize the string below. @@ -2595,13 +2595,13 @@ class ImagePut { ; C source code - https://godbolt.org/z/EqfK7fvr5 static code := 0 if !code { - code_str := (A_PtrSize == 4) + b64 := (A_PtrSize == 4) ? "VYnlVotFDIt1EFOLTRSLXQgBxjnwcyCKEIPBAkDA6gQPttKKFBOIUf6KUP+D4g+KFBOIUf/r3FteXcM=" : "SQHQTDnCcyWKAkmDwQJI/8LA6AQPtsCKBAFBiEH+ikL/g+APigQBQYhB/+vWww==" - code_size := StrLen(RTrim(code_str, "=")) * 3 // 4 - code := DllCall("GlobalAlloc", "uint", 0, "uptr", code_size, "ptr") - DllCall("VirtualProtect", "ptr", code, "ptr", code_size, "uint", 0x40, "uint*", code_old:=0) - DllCall("crypt32\CryptStringToBinary", "str", code_str, "uint", 0, "uint", 0x1, "ptr", code, "uint*", code_size, "ptr", 0, "ptr", 0) + s64 := StrLen(RTrim(b64, "=")) * 3 // 4 + code := DllCall("GlobalAlloc", "uint", 0, "uptr", s64, "ptr") + DllCall("crypt32\CryptStringToBinary", "str", b64, "uint", 0, "uint", 0x1, "ptr", code, "uint*", s64, "ptr", 0, "ptr", 0) + DllCall("VirtualProtect", "ptr", code, "ptr", s64, "uint", 0x40, "uint*", op:=0) } ; Default to lowercase hex values. Or capitalize the string below. diff --git a/ImagePut.ahk b/ImagePut.ahk index f6e28e95..8b3f83ee 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1747,21 +1747,20 @@ class ImagePut { , "ptr", BitmapData) Scan0 := NumGet(BitmapData, 16, "ptr") - ; Generate machine code. - static bin := 0 - if !bin { - ; C source code - https://godbolt.org/z/rvTWqrqv6 - code := (A_PtrSize == 4) - ? "VYnli0UIi1UMi00QjRSQOdBzDzkIdQbHAAAAAACDwATr7V3D" - : "idJIjQSRSDnBcxFEOQF1BscBAAAAAEiDwQTr6sM=" - size := StrLen(RTrim(code, "=")) * 3 // 4 - bin := DllCall("GlobalAlloc", "uint", 0, "uptr", size, "ptr") - DllCall("VirtualProtect", "ptr", bin, "ptr", size, "uint", 0x40, "uint*", &old:=0) - DllCall("crypt32\CryptStringToBinary", "str", code, "uint", 0, "uint", 0x1, "ptr", bin, "uint*", size, "ptr", 0, "ptr", 0) + ; C source code - https://godbolt.org/z/nrv5Yr3Y3 + static code := 0 + if !code { + b64 := (A_PtrSize == 4) + ? "VYnli0UIi1UMi00QOdBzDzkIdQbHAAAAAACDwATr7V3D" + : "SDnRcw9EOQF1BDHAiQFIg8EE6+zD" + s64 := StrLen(RTrim(b64, "=")) * 3 // 4 + code := DllCall("GlobalAlloc", "uint", 0, "uptr", s64, "ptr") + DllCall("crypt32\CryptStringToBinary", "str", b64, "uint", 0, "uint", 0x1, "ptr", code, "uint*", s64, "ptr", 0, "ptr", 0) + DllCall("VirtualProtect", "ptr", code, "ptr", s64, "uint", 0x40, "uint*", &op:=0) } - ; Call colorkey. - DllCall(bin, "ptr", Scan0, "uint", width * height, "uint", NumGet(Scan0, "uint")) + ; Sample the top-left pixel and set all matching pixels to be transparent. + DllCall(code, "ptr", Scan0, "ptr", Scan0 + 4*width*height, "uint", NumGet(Scan0+0, "uint")) ; Write pixels to bitmap. DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", BitmapData) @@ -1943,12 +1942,12 @@ class ImagePut { : ImagePut.show(this.pBitmap, title, pos, style, styleEx, parent) } - Base64Put(code) { - size := StrLen(RTrim(code, "=")) * 3 // 4 - bin := DllCall("GlobalAlloc", "uint", 0, "uptr", size, "ptr") - DllCall("VirtualProtect", "ptr", bin, "ptr", size, "uint", 0x40, "uint*", &old:=0) - DllCall("crypt32\CryptStringToBinary", "str", code, "uint", 0, "uint", 0x1, "ptr", bin, "uint*", size, "ptr", 0, "ptr", 0) - return bin + Base64Put(b64) { + s64 := StrLen(RTrim(b64, "=")) * 3 // 4 + code := DllCall("GlobalAlloc", "uint", 0, "uptr", s64, "ptr") + DllCall("crypt32\CryptStringToBinary", "str", b64, "uint", 0, "uint", 0x1, "ptr", code, "uint*", s64, "ptr", 0, "ptr", 0) + DllCall("VirtualProtect", "ptr", code, "ptr", s64, "uint", 0x40, "uint*", &op:=0) + return code } CPUID() { @@ -1956,21 +1955,21 @@ class ImagePut { if not cpuid { ; C source code - https://godbolt.org/z/1YPd6jz61 - code := (A_PtrSize == 4) + b64 := (A_PtrSize == 4) ? "VYnlV4t9EFaLdQhTiw+LBg+iiQaLRQyJGItFFIkPiRBbXl9dww==" : "U4sBSYnKSYnTQYsID6JBiQJBiRtBiQhBiRFbww==" - size := StrLen(RTrim(code, "=")) * 3 // 4 - bin := DllCall("GlobalAlloc", "uint", 0, "uptr", size, "ptr") - DllCall("VirtualProtect", "ptr", bin, "ptr", size, "uint", 0x40, "uint*", &old:=0) - DllCall("crypt32\CryptStringToBinary", "str", code, "uint", 0, "uint", 0x1, "ptr", bin, "uint*", size, "ptr", 0, "ptr", 0) + s64 := StrLen(RTrim(b64, "=")) * 3 // 4 + code := DllCall("GlobalAlloc", "uint", 0, "uptr", s64, "ptr") + DllCall("crypt32\CryptStringToBinary", "str", b64, "uint", 0, "uint", 0x1, "ptr", code, "uint*", s64, "ptr", 0, "ptr", 0) + DllCall("VirtualProtect", "ptr", code, "ptr", s64, "uint", 0x40, "uint*", &op:=0) ; Set eax flag to 1 to retrieve supported CPU features. ; See this for CPU features: https://wiki.osdev.org/CPUID ; Also see page 591: https://www.amd.com/system/files/TechDocs/24594.pdf - DllCall(bin, "uint*", &a := 1, "uint*", &b := 0, "uint*", &c := 0, "uint*", &d := 0) + DllCall(code, "uint*", &a := 1, "uint*", &b := 0, "uint*", &c := 0, "uint*", &d := 0) ; Free memory. - DllCall("GlobalFree", "ptr", bin) + DllCall("GlobalFree", "ptr", code) ; To check for SSE2 use the following code example: ; if cpuid().edx[26] == True @@ -2774,13 +2773,13 @@ class ImagePut { ; C source code - https://godbolt.org/z/EqfK7fvr5 static code := 0 if !code { - code_str := (A_PtrSize == 4) + b64 := (A_PtrSize == 4) ? "VYnlVotFDIt1EFOLTRSLXQgBxjnwcyCKEIPBAkDA6gQPttKKFBOIUf6KUP+D4g+KFBOIUf/r3FteXcM=" - : "SQHQTDnCcyWKAkmDwQJI/8LA6AQPtsCKBAFBiEH+ikL/g+APigQBQYhB/+vWww==" - code_size := StrLen(RTrim(code_str, "=")) * 3 // 4 - code := DllCall("GlobalAlloc", "uint", 0, "uptr", code_size, "ptr") - DllCall("VirtualProtect", "ptr", code, "ptr", code_size, "uint", 0x40, "uint*", code_old:=0) - DllCall("crypt32\CryptStringToBinary", "str", code_str, "uint", 0, "uint", 0x1, "ptr", code, "uint*", code_size, "ptr", 0, "ptr", 0) + : "SInISQHQTDnCcyiKCkmDwQJI/8JBicqD4Q9BwOoERQ+20kaKFBBFiFH+igwIQYhJ/+vTww==" + s64 := StrLen(RTrim(b64, "=")) * 3 // 4 + code := DllCall("GlobalAlloc", "uint", 0, "uptr", s64, "ptr") + DllCall("crypt32\CryptStringToBinary", "str", b64, "uint", 0, "uint", 0x1, "ptr", code, "uint*", s64, "ptr", 0, "ptr", 0) + DllCall("VirtualProtect", "ptr", code, "ptr", s64, "uint", 0x40, "uint*", &op:=0) } ; Default to lowercase hex values. Or capitalize the string below. @@ -2810,13 +2809,13 @@ class ImagePut { ; C source code - https://godbolt.org/z/EqfK7fvr5 static code := 0 if !code { - code_str := (A_PtrSize == 4) + b64 := (A_PtrSize == 4) ? "VYnlVotFDIt1EFOLTRSLXQgBxjnwcyCKEIPBAkDA6gQPttKKFBOIUf6KUP+D4g+KFBOIUf/r3FteXcM=" : "SQHQTDnCcyWKAkmDwQJI/8LA6AQPtsCKBAFBiEH+ikL/g+APigQBQYhB/+vWww==" - code_size := StrLen(RTrim(code_str, "=")) * 3 // 4 - code := DllCall("GlobalAlloc", "uint", 0, "uptr", code_size, "ptr") - DllCall("VirtualProtect", "ptr", code, "ptr", code_size, "uint", 0x40, "uint*", code_old:=0) - DllCall("crypt32\CryptStringToBinary", "str", code_str, "uint", 0, "uint", 0x1, "ptr", code, "uint*", code_size, "ptr", 0, "ptr", 0) + s64 := StrLen(RTrim(b64, "=")) * 3 // 4 + code := DllCall("GlobalAlloc", "uint", 0, "uptr", s64, "ptr") + DllCall("crypt32\CryptStringToBinary", "str", b64, "uint", 0, "uint", 0x1, "ptr", code, "uint*", s64, "ptr", 0, "ptr", 0) + DllCall("VirtualProtect", "ptr", code, "ptr", s64, "uint", 0x40, "uint*", &op:=0) } ; Default to lowercase hex values. Or capitalize the string below. From a6bb333e1a941122c7c3e6accbba42de05126b26 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 24 Jul 2022 18:58:09 -0400 Subject: [PATCH 331/492] add whitespace --- ImagePut (for v1).ahk | 214 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 5ef708fa..90ee0d1c 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -827,6 +827,220 @@ class ImagePut { ; to do } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + from_screenshot(image) { ; Thanks tic - https://www.autohotkey.com/boards/viewtopic.php?t=6517 From 62855335a5fcaa46ba5921b9ab3d8e12844c4ecb Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 24 Jul 2022 20:02:44 -0400 Subject: [PATCH 332/492] Refactor put_buffer to create a global pointer from BitmapBuffer's __New() --- ImagePut (for v1).ahk | 67 +++++++++++++++++++++++-------------------- ImagePut.ahk | 67 +++++++++++++++++++++++-------------------- 2 files changed, 72 insertions(+), 62 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 90ee0d1c..7b1af297 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1870,53 +1870,58 @@ class ImagePut { } put_buffer(pBitmap) { - return new ImagePut.BitmapBuffer(pBitmap) + ; Get Bitmap width and height. + DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) + DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) + + ; Allocate global memory. + size := 4 * width * height + ptr := DllCall("GlobalAlloc", "uint", 0, "uptr", size, "ptr") + + ; Create a pixel buffer. + VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 + NumPut( width, Rect, 8, "uint") ; Width + NumPut( height, Rect, 12, "uint") ; Height + VarSetCapacity(BitmapData, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + NumPut( 4 * width, BitmapData, 8, "int") ; Stride + NumPut( ptr, BitmapData, 16, "ptr") ; Scan0 + DllCall("gdiplus\GdipBitmapLockBits" + , "ptr", pBitmap + , "ptr", &Rect + , "uint", 5 ; ImageLockMode.UserInputBuffer | ImageLockMode.ReadOnly + , "int", 0x26200A ; Format32bppArgb + , "ptr", &BitmapData) + + ; Write pixels to global memory. + DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", &BitmapData) + + ; Free the pixels later. + free := Func("MsgBox").bind("hello world") ; Func("DllCall").bind("GlobalFree", "ptr", ptr) + + return new ImagePut.BitmapBuffer(ptr, size, width, height, free) } class BitmapBuffer { - __New(SourceBitmap) { + __New(ptr, size, width, height, free:="") { ImagePut.gdiplusStartup() - ; Get Bitmap width and height. - DllCall("gdiplus\GdipGetImageWidth", "ptr", SourceBitmap, "uint*", width:=0) - DllCall("gdiplus\GdipGetImageHeight", "ptr", SourceBitmap, "uint*", height:=0) - - ; Allocate global memory. - size := 4 * width * height - ptr := DllCall("GlobalAlloc", "uint", 0, "uptr", size, "ptr") - ; Create a pBitmap on saved memory. DllCall("gdiplus\GdipCreateBitmapFromScan0" - , "int", width, "int", height, "int", 4 * width, "int", 0x26200A, "ptr", ptr, "ptr*", pBitmap:=0) - - ; Create a pixel buffer. - VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 - NumPut( width, Rect, 8, "uint") ; Width - NumPut( height, Rect, 12, "uint") ; Height - VarSetCapacity(BitmapData, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 - NumPut( 4 * width, BitmapData, 8, "int") ; Stride - NumPut( ptr, BitmapData, 16, "ptr") ; Scan0 - DllCall("gdiplus\GdipBitmapLockBits" - , "ptr", SourceBitmap - , "ptr", &Rect - , "uint", 5 ; ImageLockMode.UserInputBuffer | ImageLockMode.ReadOnly - , "int", 0x26200A ; Format32bppArgb - , "ptr", &BitmapData) - - ; Write pixels to bitmap. - DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", SourceBitmap, "ptr", &BitmapData) + , "int", width, "int", height, "int", size // height, "int", 0x26200A, "ptr", ptr, "ptr*", pBitmap:=0) - this.width := width - this.height := height + ; Wrap the pointer without copying the data. this.ptr := ptr this.size := size + this.width := width + this.height := height + this.free := free this.pBitmap := pBitmap } __Delete() { DllCall("gdiplus\GdipDisposeImage", "ptr", this.pBitmap) - DllCall("GlobalFree", "ptr", this.ptr) + IsObject(this.free) && this.free.call() IsObject(ImagePut) && ImagePut.gdiplusShutdown() } diff --git a/ImagePut.ahk b/ImagePut.ahk index 8b3f83ee..478099bd 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1870,53 +1870,58 @@ class ImagePut { } static put_buffer(pBitmap) { - return ImagePut.BitmapBuffer(pBitmap) + ; Get Bitmap width and height. + DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) + DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) + + ; Allocate global memory. + size := 4 * width * height + ptr := DllCall("GlobalAlloc", "uint", 0, "uptr", size, "ptr") + + ; Fill a pixel buffer. + Rect := Buffer(16, 0) ; sizeof(Rect) = 16 + NumPut( "uint", width, Rect, 8) ; Width + NumPut( "uint", height, Rect, 12) ; Height + BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + NumPut( "int", 4 * width, BitmapData, 8) ; Stride + NumPut( "ptr", ptr, BitmapData, 16) ; Scan0 + DllCall("gdiplus\GdipBitmapLockBits" + , "ptr", pBitmap + , "ptr", Rect + , "uint", 5 ; ImageLockMode.UserInputBuffer | ImageLockMode.ReadOnly + , "int", 0x26200A ; Format32bppArgb + , "ptr", BitmapData) + + ; Write pixels to global memory. + DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", BitmapData) + + ; Free the pixels later. + free := DllCall.bind("GlobalFree", "ptr", ptr) + + return ImagePut.BitmapBuffer(ptr, size, width, height, free) } class BitmapBuffer { - __New(SourceBitmap) { + __New(ptr, size, width, height, free:="") { ImagePut.gdiplusStartup() - ; Get Bitmap width and height. - DllCall("gdiplus\GdipGetImageWidth", "ptr", SourceBitmap, "uint*", &width:=0) - DllCall("gdiplus\GdipGetImageHeight", "ptr", SourceBitmap, "uint*", &height:=0) - - ; Allocate global memory. - size := 4 * width * height - ptr := DllCall("GlobalAlloc", "uint", 0, "uptr", size, "ptr") - ; Create a pBitmap on saved memory. DllCall("gdiplus\GdipCreateBitmapFromScan0" - , "int", width, "int", height, "int", 4 * width, "int", 0x26200A, "ptr", ptr, "ptr*", &pBitmap:=0) - - ; Fill a pixel buffer. - Rect := Buffer(16, 0) ; sizeof(Rect) = 16 - NumPut( "uint", width, Rect, 8) ; Width - NumPut( "uint", height, Rect, 12) ; Height - BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 - NumPut( "int", 4 * width, BitmapData, 8) ; Stride - NumPut( "ptr", ptr, BitmapData, 16) ; Scan0 - DllCall("gdiplus\GdipBitmapLockBits" - , "ptr", SourceBitmap - , "ptr", Rect - , "uint", 5 ; ImageLockMode.UserInputBuffer | ImageLockMode.ReadOnly - , "int", 0x26200A ; Format32bppArgb - , "ptr", BitmapData) - - ; Write pixels to bitmap. - DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", SourceBitmap, "ptr", BitmapData) + , "int", width, "int", height, "int", size // height, "int", 0x26200A, "ptr", ptr, "ptr*", &pBitmap:=0) - this.width := width - this.height := height + ; Wrap the pointer without copying the data. this.ptr := ptr this.size := size + this.width := width + this.height := height + this.free := free this.pBitmap := pBitmap } __Delete() { DllCall("gdiplus\GdipDisposeImage", "ptr", this.pBitmap) - DllCall("GlobalFree", "ptr", this.ptr) + IsObject(this.free) && this.free() IsObject(ImagePut) && ImagePut.gdiplusShutdown() } From 0609b01f369257f0d8f8d1bb5d064a59b08b4b45 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 25 Jul 2022 10:50:15 -0400 Subject: [PATCH 333/492] C source files --- source/from_sprite.c | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 source/from_sprite.c diff --git a/source/from_sprite.c b/source/from_sprite.c new file mode 100644 index 00000000..d446c901 --- /dev/null +++ b/source/from_sprite.c @@ -0,0 +1,7 @@ +void from_sprite(unsigned int * start, unsigned int * end, unsigned int key) { + while (start < end) { + if (*start == key) + *start = 0x00000000; + start++; + } +} \ No newline at end of file From a884945d3c0de676ef19ed6c3a2f4be9f0f481d9 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 25 Jul 2022 23:07:20 -0400 Subject: [PATCH 334/492] Save() produces a 32-bit ARGB uncompressed bitmap --- ImagePut (for v1).ahk | 54 +++++++++++++++++++++++++++++++++++++++++++ ImagePut.ahk | 54 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 7b1af297..a58210d1 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1947,6 +1947,60 @@ class ImagePut { : ImagePut.show(this.pBitmap, title, pos, style, styleEx, parent) } + Save(filepath := "", quality := "") { + + ; Process filepath and set extension. + extension := "bmp" + ImagePut.select_filepath(filepath, extension) + + ; If extension is not .bmp, use put_file routine. + if (extension != "bmp") + return ImagePut.put_file(this.pBitmap, filepath, quality) + + ; Save header info. + static bm := 0 + if !bm { + VarSetCapacity(bm, 54) + + StrPut("BM", &bm, "CP0") ; identifier + NumPut(54+this.size, bm, 2, "uint") ; file size + NumPut( 0, bm, 6, "uint") ; reserved + NumPut( 54, bm, 10, "uint") ; bitmap data offset + + ; BITMAPINFOHEADER struct + NumPut( 40, bm, 14, "uint") ; Size + NumPut( this.width, bm, 18, "uint") ; Width + NumPut(-this.height, bm, 22, "int") ; Height - Negative so (0, 0) is top-left. + NumPut( 1, bm, 26, "ushort") ; Planes + NumPut( 32, bm, 28, "ushort") ; BitCount / BitsPerPixel + + NumPut( 0, bm, 30, "uint") ; biCompression + NumPut( this.size, bm, 34, "uint") ; biSizeImage + NumPut( 0, bm, 38, "int") ; biXPelsPerMeter + NumPut( 0, bm, 42, "int") ; biYPelsPerMeter + NumPut( 0, bm, 46, "uint") ; biClrUsed + NumPut( 0, bm, 50, "uint") ; biClrImportant + + + } + + loop + try + if file := FileOpen(filepath, "w") + break + else throw + catch + if A_Index < 6 + Sleep (2**(A_Index-1) * 30) + else throw + + file.RawWrite(bm, 54) ; Writes 54 bytes of bitmap file header. + file.RawWrite(this.ptr+0, this.size) ; Writes raw 32-bit ARGB pixel data. + file.Close() + + return filepath + } + Base64Put(b64) { s64 := StrLen(RTrim(b64, "=")) * 3 // 4 code := DllCall("GlobalAlloc", "uint", 0, "uptr", s64, "ptr") diff --git a/ImagePut.ahk b/ImagePut.ahk index 478099bd..f6acaa0a 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1947,6 +1947,60 @@ class ImagePut { : ImagePut.show(this.pBitmap, title, pos, style, styleEx, parent) } + Save(filepath := "", quality := "") { + + ; Process filepath and set extension. + extension := "bmp" + ImagePut.select_filepath(&filepath, &extension) + + ; If extension is not .bmp, use put_file routine. + if (extension != "bmp") + return ImagePut.put_file(this.pBitmap, filepath, quality) + + ; Save header info. + static bm := CreateBitmapHeader() + CreateBitmapHeader() { + bm := Buffer(54) + + StrPut("BM", bm, "CP0") ; identifier + NumPut( "uint", 54+this.size, bm, 2) ; file size + NumPut( "uint", 0, bm, 6) ; reserved + NumPut( "uint", 54, bm, 10) ; bitmap data offset + + ; BITMAPINFOHEADER struct + NumPut( "uint", 40, bm, 14) ; Size + NumPut( "uint", this.width, bm, 18) ; Width + NumPut( "int", -this.height, bm, 22) ; Height - Negative so (0, 0) is top-left. + NumPut("ushort", 1, bm, 26) ; Planes + NumPut("ushort", 32, bm, 28) ; BitCount / BitsPerPixel + + NumPut( "uint", 0, bm, 30) ; biCompression + NumPut( "uint", this.size, bm, 34) ; biSizeImage + NumPut( "int", 0, bm, 38) ; biXPelsPerMeter + NumPut( "int", 0, bm, 42) ; biYPelsPerMeter + NumPut( "uint", 0, bm, 46) ; biClrUsed + NumPut( "uint", 0, bm, 50) ; biClrImportant + + return bm + } + + loop + try + if file := FileOpen(filepath, "w") + break + else throw + catch + if A_Index < 6 + Sleep (2**(A_Index-1) * 30) + else throw + + file.RawWrite(bm) ; Writes 54 bytes of bitmap file header. + file.RawWrite(this) ; Writes raw 32-bit ARGB pixel data. + file.Close() + + return filepath + } + Base64Put(b64) { s64 := StrLen(RTrim(b64, "=")) * 3 // 4 code := DllCall("GlobalAlloc", "uint", 0, "uptr", s64, "ptr") From b907d9748eaf71fb3c51d4ec7364647c5108da0b Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 26 Jul 2022 14:58:28 -0400 Subject: [PATCH 335/492] Disable complaints that the class is not found due to alphabetical object destruction order --- ImagePut (for v1).ahk | 4 ++-- ImagePut.ahk | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index a58210d1..2ade58c8 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1896,7 +1896,7 @@ class ImagePut { DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", &BitmapData) ; Free the pixels later. - free := Func("MsgBox").bind("hello world") ; Func("DllCall").bind("GlobalFree", "ptr", ptr) + free := Func("DllCall").bind("GlobalFree", "ptr", ptr) return new ImagePut.BitmapBuffer(ptr, size, width, height, free) } @@ -1921,7 +1921,7 @@ class ImagePut { __Delete() { DllCall("gdiplus\GdipDisposeImage", "ptr", this.pBitmap) - IsObject(this.free) && this.free.call() + IsObject(ImagePut) && IsFunc(this.free.call) && this.free.call() IsObject(ImagePut) && ImagePut.gdiplusShutdown() } diff --git a/ImagePut.ahk b/ImagePut.ahk index f6acaa0a..41a222dd 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1921,7 +1921,7 @@ class ImagePut { __Delete() { DllCall("gdiplus\GdipDisposeImage", "ptr", this.pBitmap) - IsObject(this.free) && this.free() + IsObject(ImagePut) && HasMethod(this.free) && this.free() IsObject(ImagePut) && ImagePut.gdiplusShutdown() } From ce060b728854f55f74c5b5ea03bbfa6740cd869e Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 29 Jul 2022 20:05:00 -0400 Subject: [PATCH 336/492] Fixes ImageSearch erroneously creating a buffer from buffer --- ImagePut (for v1).ahk | 3 ++- ImagePut.ahk | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 2ade58c8..39956770 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2153,7 +2153,8 @@ class ImagePut { . "AnVITInQMdJMKdhIwfgC9/FBOdV+NUE5wH4wTInSTInIRTH2QTn+dCtMOeBzEkSLOkQ5OHUVSIPCBEiDwATr6UgB2kgB8EH/xuvZ" . "SYPCBOulSYnqTInQW15fXUFcQV1BXkFfww==") - if ImagePut.ImageType(image) != "buffer" + ; Check for a .pBitmap property + if !(IsObject(image) && ObjHasKey(image, "pBitmap")) image := ImagePutBuffer(image) ; Search for the address of the first matching image. diff --git a/ImagePut.ahk b/ImagePut.ahk index 41a222dd..a62cf65f 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2153,7 +2153,8 @@ class ImagePut { . "AnVITInQMdJMKdhIwfgC9/FBOdV+NUE5wH4wTInSTInIRTH2QTn+dCtMOeBzEkSLOkQ5OHUVSIPCBEiDwATr6UgB2kgB8EH/xuvZ" . "SYPCBOulSYnqTInQW15fXUFcQV1BXkFfww==") - if ImagePut.ImageType(image) != "buffer" + ; Check for a .pBitmap property + if !(IsObject(image) && ObjHasOwnProp(image, "pBitmap")) image := ImagePutBuffer(image) ; Search for the address of the first matching image. From 5491bf97f7e0d14b42ec899010dedd72444df023 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 29 Jul 2022 20:21:16 -0400 Subject: [PATCH 337/492] Avoid exporting the pBitmap for buffers --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 39956770..053e1a47 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -206,7 +206,7 @@ class ImagePut { coimage := this.BitmapToCoimage(cotype, pBitmap, p*) ; Clean up the pBitmap copy. Export raw pointers if requested. - if !(cotype = "bitmap" || cotype = "buffer") + if !(cotype = "bitmap") DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) } diff --git a/ImagePut.ahk b/ImagePut.ahk index a62cf65f..332ff487 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -206,7 +206,7 @@ class ImagePut { coimage := this.BitmapToCoimage(cotype, pBitmap, p*) ; Clean up the pBitmap copy. Export raw pointers if requested. - if !(cotype = "bitmap" || cotype = "buffer") + if !(cotype = "bitmap") DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) } From 1354ff373547543bb6f741e114bf46efc87f744e Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 29 Jul 2022 20:43:17 -0400 Subject: [PATCH 338/492] Fixes calling bound functions --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 053e1a47..3f607eb1 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1921,7 +1921,7 @@ class ImagePut { __Delete() { DllCall("gdiplus\GdipDisposeImage", "ptr", this.pBitmap) - IsObject(ImagePut) && IsFunc(this.free.call) && this.free.call() + IsObject(ImagePut) && this.free && this.free.call() IsObject(ImagePut) && ImagePut.gdiplusShutdown() } diff --git a/ImagePut.ahk b/ImagePut.ahk index 332ff487..c772c0b0 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1921,7 +1921,7 @@ class ImagePut { __Delete() { DllCall("gdiplus\GdipDisposeImage", "ptr", this.pBitmap) - IsObject(ImagePut) && HasMethod(this.free) && this.free() + IsObject(ImagePut) && HasMethod(this.free) && this.free.call() IsObject(ImagePut) && ImagePut.gdiplusShutdown() } From eebfac218332ffb4f50a9071993e69fa32cf3d56 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 22 Aug 2022 22:30:32 -0400 Subject: [PATCH 339/492] Allow ClipboardAll (no parenthesis) in v2 --- ImagePut (for v1).ahk | 2 ++ ImagePut.ahk | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 3f607eb1..c5ea1b44 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -287,6 +287,8 @@ class ImagePut { + + ; A "clipboard_png" is a pointer to a PNG stream saved as the "png" clipboard format. if DllCall("IsClipboardFormatAvailable", "uint", DllCall("RegisterClipboardFormat", "str", "png", "uint")) return "clipboard_png" diff --git a/ImagePut.ahk b/ImagePut.ahk index c772c0b0..48119909 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -286,7 +286,9 @@ class ImagePut { throw Error("Image data is an empty string.") if IsObject(image) { - if (image.base.HasOwnProp("__class") && image.base.__class == "ClipboardAll") { + if (image.prototype.HasOwnProp("__class") && image.prototype.__class == "ClipboardAll" + || image.base.HasOwnProp("__class") && image.base.__class == "ClipboardAll") { + ; A "clipboard_png" is a pointer to a PNG stream saved as the "png" clipboard format. if DllCall("IsClipboardFormatAvailable", "uint", DllCall("RegisterClipboardFormat", "str", "png", "uint")) return "clipboard_png" From 309697f3f99ef8904e0192861f1a69ba65afd654 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 22 Aug 2022 23:33:29 -0400 Subject: [PATCH 340/492] Remove global variables from ImagePut drag & drop --- ImagePut (for v1).ahk | 5 ++++- ImagePut.ahk | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index c5ea1b44..124d58ab 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -3555,7 +3555,10 @@ class ImageEqual extends ImagePut { ; Drag and drop files directly onto this script file. -if (A_Args.length() > 0 and A_LineFile == A_ScriptFullPath) { +if (A_Args.length() > 0 and A_LineFile == A_ScriptFullPath) + ImagePut_dropfiles() + +ImagePut_dropfiles() { filepath := "" for each, arg in A_Args { filepath .= arg . A_Space diff --git a/ImagePut.ahk b/ImagePut.ahk index 48119909..416328b2 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -3555,7 +3555,10 @@ class ImageEqual extends ImagePut { ; Drag and drop files directly onto this script file. -if (A_Args.length > 0 and A_LineFile == A_ScriptFullPath) { +if (A_Args.length > 0 and A_LineFile == A_ScriptFullPath) + ImagePut_dropfiles() + +ImagePut_dropfiles() { filepath := "" for each, arg in A_Args { filepath .= arg . A_Space From c214d942467d316317aa935237f14f37daf7db49 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 27 Aug 2022 22:32:42 -0400 Subject: [PATCH 341/492] place main code at bottom --- ImagePut (for v1).ahk | 9 +++++---- ImagePut.ahk | 10 +++++----- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 124d58ab..eb0c7647 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -3554,9 +3554,6 @@ class ImageEqual extends ImagePut { } ; End of ImageEqual class. -; Drag and drop files directly onto this script file. -if (A_Args.length() > 0 and A_LineFile == A_ScriptFullPath) - ImagePut_dropfiles() ImagePut_dropfiles() { filepath := "" @@ -3568,4 +3565,8 @@ ImagePut_dropfiles() { filepath := "" } } -} \ No newline at end of file +} + +; Drag and drop files directly onto this script file. +if (A_Args.length() > 0 and A_LineFile == A_ScriptFullPath) + ImagePut_dropfiles() \ No newline at end of file diff --git a/ImagePut.ahk b/ImagePut.ahk index 416328b2..40efbccc 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -3554,10 +3554,6 @@ class ImageEqual extends ImagePut { } ; End of ImageEqual class. -; Drag and drop files directly onto this script file. -if (A_Args.length > 0 and A_LineFile == A_ScriptFullPath) - ImagePut_dropfiles() - ImagePut_dropfiles() { filepath := "" for each, arg in A_Args { @@ -3568,4 +3564,8 @@ ImagePut_dropfiles() { filepath := "" } } -} \ No newline at end of file +} + +; Drag and drop files directly onto this script file. +if (A_Args.length > 0 and A_LineFile == A_ScriptFullPath) + ImagePut_dropfiles() \ No newline at end of file From 984b0ee5a895298b0e957256a5a35750e74f8f80 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 27 Aug 2022 23:32:50 -0400 Subject: [PATCH 342/492] shorten URLs again --- ImagePut (for v1).ahk | 10 +++++----- ImagePut.ahk | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index eb0c7647..9640972d 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1696,7 +1696,7 @@ class ImagePut { } from_wicBitmap(image) { - ; IWICBitmapSource::GetSize - https://github.com/iseahound/winsdk-10/blob/master/Include/10.0.16299.0/um/wincodec.h#L1304 + ; IWICBitmapSource::GetSize - https://github.com/iseahound/10/blob/win/10.0.16299.0/um/wincodec.h#L1304 DllCall(NumGet(NumGet(image + 0) + A_PtrSize*3), "ptr", image, "uint*", width:=0, "uint*", height:=0) ; Intialize an empty pBitmap using managed memory. @@ -1717,7 +1717,7 @@ class ImagePut { Scan0 := NumGet(BitmapData, 16, "ptr") stride := NumGet(BitmapData, 8, "int") - ; IWICBitmapSource::CopyPixels - https://github.com/iseahound/winsdk-10/blob/master/Include/10.0.16299.0/um/wincodec.h#L1322 + ; IWICBitmapSource::CopyPixels - https://github.com/iseahound/10/blob/win/10.0.16299.0/um/wincodec.h#L1322 DllCall(NumGet(NumGet(image + 0) + A_PtrSize*7), "ptr", image, "ptr", &Rect, "uint", stride, "uint", stride * height, "ptr", Scan0) ; Write pixels to bitmap. @@ -3105,7 +3105,7 @@ class ImagePut { IWICImagingFactory := ComObjCreate(CLSID_WICImagingFactory := "{CACAF262-9370-4615-A13B-9F5539DA4C0A}", IID_IWICImagingFactory := "{EC5EC8A9-C395-4314-9C77-54D7A935FF70}") ; WICBitmapNoCache must be 1! - ; IWICImagingFactory::CreateBitmap - https://github.com/iseahound/winsdk-10/blob/master/Include/10.0.16299.0/um/wincodec.h#L6447 + ; IWICImagingFactory::CreateBitmap - https://github.com/iseahound/10/blob/win/10.0.16299.0/um/wincodec.h#L6447 DllCall("ole32\CLSIDFromString", "wstr", GUID_WICPixelFormat32bppBGRA := "{6fddc324-4e03-4bfe-b185-3d77768dc90f}", "ptr", &CLSID := VarSetCapacity(CLSID, 16), "uint") DllCall(NumGet(NumGet(IWICImagingFactory + 0) + A_PtrSize*17), "ptr", IWICImagingFactory, "uint", width, "uint", height, "ptr", &CLSID, "int", 1, "ptr*", wicBitmap:=0) @@ -3113,10 +3113,10 @@ class ImagePut { NumPut( width, Rect, 8, "uint") ; Width NumPut( height, Rect, 12, "uint") ; Height - ; IWICBitmap::Lock - https://github.com/iseahound/winsdk-10/blob/master/Include/10.0.16299.0/um/wincodec.h#L2232 + ; IWICBitmap::Lock - https://github.com/iseahound/10/blob/win/10.0.16299.0/um/wincodec.h#L2232 DllCall(NumGet(NumGet(wicBitmap + 0) + A_PtrSize*8), "ptr", wicBitmap, "ptr", &Rect, "uint", 0x1, "ptr*", Lock:=0) - ; IWICBitmapLock::GetDataPointer - https://github.com/iseahound/winsdk-10/blob/master/Include/10.0.16299.0/um/wincodec.h#L2104 + ; IWICBitmapLock::GetDataPointer - https://github.com/iseahound/10/blob/win/10.0.16299.0/um/wincodec.h#L2104 DllCall(NumGet(NumGet(Lock + 0) + A_PtrSize*5), "ptr", Lock, "uint*", size:=0, "ptr*", Scan0:=0) VarSetCapacity(BitmapData, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 diff --git a/ImagePut.ahk b/ImagePut.ahk index 40efbccc..31866286 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1696,7 +1696,7 @@ class ImagePut { } static from_wicBitmap(image) { - ; IWICBitmapSource::GetSize - https://github.com/iseahound/winsdk-10/blob/master/Include/10.0.16299.0/um/wincodec.h#L1304 + ; IWICBitmapSource::GetSize - https://github.com/iseahound/10/blob/win/10.0.16299.0/um/wincodec.h#L1304 ComCall(3, image, "uint*", &width:=0, "uint*", &height:=0) ; Intialize an empty pBitmap using managed memory. @@ -1717,7 +1717,7 @@ class ImagePut { Scan0 := NumGet(BitmapData, 16, "ptr") stride := NumGet(BitmapData, 8, "int") - ; IWICBitmapSource::CopyPixels - https://github.com/iseahound/winsdk-10/blob/master/Include/10.0.16299.0/um/wincodec.h#L1322 + ; IWICBitmapSource::CopyPixels - https://github.com/iseahound/10/blob/win/10.0.16299.0/um/wincodec.h#L1322 ComCall(7, image, "ptr", Rect, "uint", stride, "uint", stride * height, "ptr", Scan0) ; Write pixels to bitmap. @@ -3105,7 +3105,7 @@ class ImagePut { IWICImagingFactory := ComObject(CLSID_WICImagingFactory := "{CACAF262-9370-4615-A13B-9F5539DA4C0A}", IID_IWICImagingFactory := "{EC5EC8A9-C395-4314-9C77-54D7A935FF70}") ; WICBitmapNoCache must be 1! - ; IWICImagingFactory::CreateBitmap - https://github.com/iseahound/winsdk-10/blob/master/Include/10.0.16299.0/um/wincodec.h#L6447 + ; IWICImagingFactory::CreateBitmap - https://github.com/iseahound/10/blob/win/10.0.16299.0/um/wincodec.h#L6447 DllCall("ole32\CLSIDFromString", "wstr", GUID_WICPixelFormat32bppBGRA := "{6fddc324-4e03-4bfe-b185-3d77768dc90f}", "ptr", CLSID := Buffer(16), "HRESULT") ComCall(17, IWICImagingFactory, "uint", width, "uint", height, "ptr", CLSID, "int", 1, "ptr*", &wicBitmap:=0) @@ -3113,10 +3113,10 @@ class ImagePut { NumPut( "uint", width, Rect, 8) ; Width NumPut( "uint", height, Rect, 12) ; Height - ; IWICBitmap::Lock - https://github.com/iseahound/winsdk-10/blob/master/Include/10.0.16299.0/um/wincodec.h#L2232 + ; IWICBitmap::Lock - https://github.com/iseahound/10/blob/win/10.0.16299.0/um/wincodec.h#L2232 ComCall(8, wicBitmap, "ptr", Rect, "uint", 0x1, "ptr*", &Lock:=0) - ; IWICBitmapLock::GetDataPointer - https://github.com/iseahound/winsdk-10/blob/master/Include/10.0.16299.0/um/wincodec.h#L2104 + ; IWICBitmapLock::GetDataPointer - https://github.com/iseahound/10/blob/win/10.0.16299.0/um/wincodec.h#L2104 ComCall(5, Lock, "uint*", &size:=0, "ptr*", &Scan0:=0) BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 From 1d391617f2de3a1070439c3749202356801f2cd1 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 29 Aug 2022 20:07:51 -0400 Subject: [PATCH 343/492] Resolve File before Window --- ImagePut (for v1).ahk | 12 ++++++++---- ImagePut.ahk | 12 ++++++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 9640972d..154ca9c3 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -311,11 +311,11 @@ class ImagePut { ; A "screenshot" is an array of 4 numbers. if (image[1] ~= "^-?\d+$" && image[2] ~= "^-?\d+$" && image[3] ~= "^-?\d+$" && image[4] ~= "^-?\d+$") return "screenshot" - } - ; A "window" is anything considered a Window Title including ahk_class and "A". - if WinExist(image) || DllCall("IsWindow", "ptr", image) - return "window" + ; A "window" is an object with an hwnd property. + if image.HasOwnProp("hwnd") + return "window" + } ; A "desktop" is a hidden window behind the desktop icons created by ImagePutDesktop. if (image = "desktop") return "desktop" @@ -341,6 +341,10 @@ class ImagePut { if FileExist(image) return "file" + ; A "window" is anything considered a Window Title including ahk_class and "A". + if WinExist(image) || DllCall("IsWindow", "ptr", image) + return "window" + ; A "hex" string is binary image data encoded into text using hexadecimal. if (StrLen(image) >= 48) && (image ~= "^\s*(?:[A-Fa-f0-9]{2})*+\s*$") return "hex" diff --git a/ImagePut.ahk b/ImagePut.ahk index 31866286..2e0f2d58 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -311,11 +311,11 @@ class ImagePut { ; A "screenshot" is an array of 4 numbers. if (image[1] ~= "^-?\d+$" && image[2] ~= "^-?\d+$" && image[3] ~= "^-?\d+$" && image[4] ~= "^-?\d+$") return "screenshot" - } - ; A "window" is anything considered a Window Title including ahk_class and "A". - if WinExist(image) - return "window" + ; A "window" is an object with an hwnd property. + if image.HasOwnProp("hwnd") + return "window" + } ; A "desktop" is a hidden window behind the desktop icons created by ImagePutDesktop. if (image = "desktop") return "desktop" @@ -341,6 +341,10 @@ class ImagePut { if FileExist(image) return "file" + ; A "window" is anything considered a Window Title including ahk_class and "A". + if WinExist(image) + return "window" + ; A "hex" string is binary image data encoded into text using hexadecimal. if (StrLen(image) >= 48) && (image ~= "^\s*(?:[A-Fa-f0-9]{2})*+\s*$") return "hex" From 116d48600867dc90da51e755ffc67e2df25195e9 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 29 Aug 2022 20:09:44 -0400 Subject: [PATCH 344/492] Use Haskey for v1 --- ImagePut (for v1).ahk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 154ca9c3..8b39a223 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -313,7 +313,7 @@ class ImagePut { return "screenshot" ; A "window" is an object with an hwnd property. - if image.HasOwnProp("hwnd") + if image.HasKey("hwnd") return "window" } ; A "desktop" is a hidden window behind the desktop icons created by ImagePutDesktop. From f20f64d9a3dbc1bf25e635ca5b2603e35f352b43 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 29 Aug 2022 20:13:57 -0400 Subject: [PATCH 345/492] Give monitor numbers higher priority --- ImagePut (for v1).ahk | 8 ++++---- ImagePut.ahk | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 8b39a223..e53aac2a 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -316,6 +316,10 @@ class ImagePut { if image.HasKey("hwnd") return "window" } + SysGet MonitorGetCount, MonitorCount ; A non-zero "monitor" number identifies each display uniquely; and 0 refers to the entire virtual screen. + if (image ~= "^\d+$" && image >= 0 && image <= MonitorGetCount) + return "monitor" + ; A "desktop" is a hidden window behind the desktop icons created by ImagePutDesktop. if (image = "desktop") return "desktop" @@ -355,10 +359,6 @@ class ImagePut { return "base64" if (image ~= "^-?\d+$") { - SysGet MonitorGetCount, MonitorCount ; A non-zero "monitor" number identifies each display uniquely; and 0 refers to the entire virtual screen. - if (image >= 0 && image <= MonitorGetCount) - return "monitor" - ; A "dc" is a handle to a GDI device context. if (DllCall("GetObjectType", "ptr", image, "uint") == 3 || DllCall("GetObjectType", "ptr", image, "uint") == 10) return "dc" diff --git a/ImagePut.ahk b/ImagePut.ahk index 2e0f2d58..3108b5ea 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -316,6 +316,10 @@ class ImagePut { if image.HasOwnProp("hwnd") return "window" } + ; A non-zero "monitor" number identifies each display uniquely; and 0 refers to the entire virtual screen. + if (image ~= "^\d+$" && image >= 0 && image <= MonitorGetCount()) + return "monitor" + ; A "desktop" is a hidden window behind the desktop icons created by ImagePutDesktop. if (image = "desktop") return "desktop" @@ -355,10 +359,6 @@ class ImagePut { return "base64" if (image ~= "^-?\d+$") { - ; A non-zero "monitor" number identifies each display uniquely; and 0 refers to the entire virtual screen. - if (image >= 0 && image <= MonitorGetCount()) - return "monitor" - ; A "dc" is a handle to a GDI device context. if (DllCall("GetObjectType", "ptr", image, "uint") == 3 || DllCall("GetObjectType", "ptr", image, "uint") == 10) return "dc" From 0d19547a5ae212864e0360ffd9c9e9e6202f2839 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 30 Aug 2022 16:29:38 -0400 Subject: [PATCH 346/492] ImagePutExplorer() --- ImagePut (for v1).ahk | 65 ++++++++++++++++++++++++++++++++++++++++++- ImagePut.ahk | 65 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 128 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index e53aac2a..a8acbd9f 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -48,6 +48,11 @@ ImagePutDesktop(image) { return ImagePut("desktop", image) } +; Puts the image into the most recently active explorer window. +ImagePutExplorer(image, default := "") { + return ImagePut("explorer", image, default) +} + ; Puts the image into a file and returns its filepath. ; filepath - Filepath + Extension | string -> *.bmp, *.gif, *.jpg, *.png, *.tiff ; quality - JPEG Quality Level | integer -> 0 - 100 @@ -175,7 +180,7 @@ class ImagePut { ; #1 - Stream intermediate. if not decode and not crop and not scale and (type ~= "^(?i:clipboard_png|pdf|url|file|stream|RandomAccessStream|hex|base64)$") - and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64|uri)$") + and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64|uri|explorer)$") and (p[1] == "") { ; For now, disallow any specification of extensions. ; Convert via stream intermediate. @@ -564,6 +569,10 @@ class ImagePut { if (cotype = "wicBitmap") return this.put_wicBitmap(pBitmap) + ; BitmapToCoimage("explorer", pBitmap, default) + if (cotype = "explorer") + return this.put_explorer(pBitmap, default) + throw Exception("Conversion from bitmap to " cotype " is not supported.") } @@ -624,6 +633,10 @@ class ImagePut { if (cotype = "RandomAccessStream") return this.set_RandomAccessStream(pStream) + ; StreamToCoimage("explorer", pStream, default) + if (cotype = "explorer") + return this.set_explorer(pStream, p1) + throw Exception("Conversion from stream to " cotype " is not supported.") } @@ -2777,6 +2790,56 @@ class ImagePut { return "A_Cursor" } + put_explorer(pBitmap, default := "") { + + ; Default directory to desktop. + (default == "") && default := A_Desktop + + ; Check if the mouse is pointing to the desktop. + MouseGetPos,,, hwnd + WinGetClass class, ahk_id %hwnd% + if (class ~= "(?i)Progman|WorkerW") + directory := A_Desktop + + ; Get path of active window. + else if (hwnd := WinExist("ahk_class ExploreWClass")) || (hwnd := WinExist("ahk_class CabinetWClass")) { + for window in ComObjCreate("Shell.Application").Windows { + if (window.hwnd == hwnd) { + try directory := window.Document.Folder.Self.Path + } + } + } + else + directory := default + + return this.put_file(pBitmap, directory) + } + + set_explorer(pStream, default := "") { + + ; Default directory to desktop. + (default == "") && default := A_Desktop + + ; Check if the mouse is pointing to the desktop. + MouseGetPos,,, hwnd + WinGetClass class, ahk_id %hwnd% + if (class ~= "(?i)Progman|WorkerW") + directory := A_Desktop + + ; Get path of active window. + else if (hwnd := WinExist("ahk_class ExploreWClass")) || (hwnd := WinExist("ahk_class CabinetWClass")) { + for window in ComObjCreate("Shell.Application").Windows { + if (window.hwnd == hwnd) { + try directory := window.Document.Folder.Self.Path + } + } + } + else + directory := default + + return this.put_file(pStream, directory) + } + put_file(pBitmap, filepath := "", quality := "") { ; Thanks tic - https://www.autohotkey.com/boards/viewtopic.php?t=6517 extension := "png" diff --git a/ImagePut.ahk b/ImagePut.ahk index 3108b5ea..182d0611 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -48,6 +48,11 @@ ImagePutDesktop(image) { return ImagePut("desktop", image) } +; Puts the image into the most recently active explorer window. +ImagePutExplorer(image, default := "") { + return ImagePut("explorer", image, default) +} + ; Puts the image into a file and returns its filepath. ; filepath - Filepath + Extension | string -> *.bmp, *.gif, *.jpg, *.png, *.tiff ; quality - JPEG Quality Level | integer -> 0 - 100 @@ -175,7 +180,7 @@ class ImagePut { ; #1 - Stream intermediate. if not decode and not crop and not scale and (type ~= "^(?i:clipboard_png|pdf|url|file|stream|RandomAccessStream|hex|base64)$") - and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64|uri)$") + and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64|uri|explorer)$") and (!p.Has(1) || p[1] == "") { ; For now, disallow any specification of extensions. ; Convert via stream intermediate. @@ -564,6 +569,10 @@ class ImagePut { if (cotype = "wicBitmap") return this.put_wicBitmap(pBitmap) + ; BitmapToCoimage("explorer", pBitmap, default) + if (cotype = "explorer") + return this.put_explorer(pBitmap, p1) + throw Error("Conversion from bitmap to " cotype " is not supported.") } @@ -624,6 +633,10 @@ class ImagePut { if (cotype = "RandomAccessStream") return this.set_RandomAccessStream(pStream) + ; StreamToCoimage("explorer", pStream, default) + if (cotype = "explorer") + return this.set_explorer(pStream, p1) + throw Error("Conversion from stream to " cotype " is not supported.") } @@ -2777,6 +2790,56 @@ class ImagePut { return "A_Cursor" } + static put_explorer(pBitmap, default := "") { + + ; Default directory to desktop. + (default == "") && default := A_Desktop + + ; Check if the mouse is pointing to the desktop. + MouseGetPos ,, &hwnd + + if WinGetClass("ahk_id" hwnd) ~= "(?i)Progman|WorkerW" + directory := A_Desktop + + ; Get path of active window. + else if (hwnd := WinExist("ahk_class ExploreWClass")) || (hwnd := WinExist("ahk_class CabinetWClass")) { + for window in ComObject("Shell.Application").Windows { + if (window.hwnd == hwnd) { + try directory := window.Document.Folder.Self.Path + } + } + } + else + directory := default + + return this.put_file(pBitmap, directory) + } + + static set_explorer(pStream, default := "") { + + ; Default directory to desktop. + (default == "") && default := A_Desktop + + ; Check if the mouse is pointing to the desktop. + MouseGetPos ,, &hwnd + + if WinGetClass("ahk_id" hwnd) ~= "(?i)Progman|WorkerW" + directory := A_Desktop + + ; Get path of active window. + else if (hwnd := WinExist("ahk_class ExploreWClass")) || (hwnd := WinExist("ahk_class CabinetWClass")) { + for window in ComObject("Shell.Application").Windows { + if (window.hwnd == hwnd) { + try directory := window.Document.Folder.Self.Path + } + } + } + else + directory := default + + return this.set_file(pStream, directory) + } + static put_file(pBitmap, filepath := "", quality := "") { ; Thanks tic - https://www.autohotkey.com/boards/viewtopic.php?t=6517 extension := "png" From 1dd8f45431b8b4d5171886fa610c83165f6dfee0 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 4 Sep 2022 00:12:18 -0400 Subject: [PATCH 347/492] ImagePutSafeArray() --- ImagePut (for v1).ahk | 61 ++++++++++++++++++++++++++++++++++++++++++- ImagePut.ahk | 61 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 120 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index a8acbd9f..e50fc0bf 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -85,6 +85,13 @@ ImagePutRandomAccessStream(image, extension := "", quality := "") { return ImagePut("RandomAccessStream", image, extension, quality) } +; Puts the image into a file format and returns a SafeArray COM Object. +; extension - File Encoding | string -> bmp, gif, jpg, png, tiff +; quality - JPEG Quality Level | integer -> 0 - 100 +ImagePutSafeArray(image, extension := "", quality := "") { + return ImagePut("safeArray", image, extension, quality) +} + ; Puts the image on the shared screen device context and returns an array of coordinates. ; screenshot - Screen Coordinates | array -> [x,y,w,h] or [0,0] ; alpha - Alpha Replacement Color | RGB -> 0xFFFFFF @@ -180,7 +187,7 @@ class ImagePut { ; #1 - Stream intermediate. if not decode and not crop and not scale and (type ~= "^(?i:clipboard_png|pdf|url|file|stream|RandomAccessStream|hex|base64)$") - and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64|uri|explorer)$") + and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64|uri|explorer|safeArray)$") and (p[1] == "") { ; For now, disallow any specification of extensions. ; Convert via stream intermediate. @@ -573,6 +580,10 @@ class ImagePut { if (cotype = "explorer") return this.put_explorer(pBitmap, default) + ; BitmapToCoimage("safeArray", pBitmap, extension, quality) + if (cotype = "safeArray") + return this.put_safeArray(pBitmap, p1, p2) + throw Exception("Conversion from bitmap to " cotype " is not supported.") } @@ -636,6 +647,10 @@ class ImagePut { ; StreamToCoimage("explorer", pStream, default) if (cotype = "explorer") return this.set_explorer(pStream, p1) + + ; StreamToCoimage("safeArray", pStream) + if (cotype = "safeArray") + return this.set_safeArray(pStream) throw Exception("Conversion from stream to " cotype " is not supported.") } @@ -3203,6 +3218,50 @@ class ImagePut { return wicBitmap } + set_safeArray(pStream) { + ; Allocate a one-dimensional SAFEARRAY based on the size of the stream. + DllCall("shlwapi\IStream_Size", "ptr", pStream, "uint64*", size:=0, "uint") + safeArray := ComObjArray(0x11, size) ; VT_ARRAY | VT_UI1 + pvData := NumGet(ComObjValue(safeArray), 8 + A_PtrSize, "ptr") + + ; Copy the stream to the SAFEARRAY. + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") + DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", pvData, "uint", size, "uint") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") + + return safeArray + } + + put_safeArray(pBitmap, extension := "", quality := "") { + ; Thanks tmplinshi - https://www.autohotkey.com/boards/viewtopic.php?p=354007#p354007 + + ; Create an IStream backed with movable memory. + hData := DllCall("GlobalAlloc", "uint", 0x2, "uptr", 0, "ptr") + DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", True, "ptr*", pStream:=0, "uint") + + ; Default extension is PNG for small sizes! + (extension == "") && extension := "png" + + ; Save pBitmap to the IStream. + this.select_codec(pBitmap, extension, quality, pCodec, ep, ci, v) + DllCall("gdiplus\GdipSaveImageToStream", "ptr", pBitmap, "ptr", pStream, "ptr", pCodec, "ptr", (ep) ? &ep : 0) + + ; Get the pointer and size of the IStream's movable memory. + pData := DllCall("GlobalLock", "ptr", hData, "ptr") + size := DllCall("GlobalSize", "ptr", pData, "uptr") + + ; Copy the encoded image to a SAFEARRAY. + safeArray := ComObjArray(0x11, size) ; VT_ARRAY | VT_UI1 + pvData := NumGet(ComObjValue(safeArray), 8 + A_PtrSize, "ptr") + DllCall("RtlMoveMemory", "ptr", pvData, "ptr", pData, "uptr", size) + + ; Release the IStream and call GlobalFree. + DllCall("GlobalUnlock", "ptr", hData) + ObjRelease(pStream) + + return safeArray + } + select_codec(pBitmap, extension, quality, ByRef pCodec, ByRef ep, ByRef ci, ByRef v) { ; Fill a buffer with the available image codec info. DllCall("gdiplus\GdipGetImageEncodersSize", "uint*", count:=0, "uint*", size:=0) diff --git a/ImagePut.ahk b/ImagePut.ahk index 182d0611..08032fa0 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -85,6 +85,13 @@ ImagePutRandomAccessStream(image, extension := "", quality := "") { return ImagePut("RandomAccessStream", image, extension, quality) } +; Puts the image into a file format and returns a SafeArray COM Object. +; extension - File Encoding | string -> bmp, gif, jpg, png, tiff +; quality - JPEG Quality Level | integer -> 0 - 100 +ImagePutSafeArray(image, extension := "", quality := "") { + return ImagePut("safeArray", image, extension, quality) +} + ; Puts the image on the shared screen device context and returns an array of coordinates. ; screenshot - Screen Coordinates | array -> [x,y,w,h] or [0,0] ; alpha - Alpha Replacement Color | RGB -> 0xFFFFFF @@ -180,7 +187,7 @@ class ImagePut { ; #1 - Stream intermediate. if not decode and not crop and not scale and (type ~= "^(?i:clipboard_png|pdf|url|file|stream|RandomAccessStream|hex|base64)$") - and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64|uri|explorer)$") + and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64|uri|explorer|safeArray)$") and (!p.Has(1) || p[1] == "") { ; For now, disallow any specification of extensions. ; Convert via stream intermediate. @@ -573,6 +580,10 @@ class ImagePut { if (cotype = "explorer") return this.put_explorer(pBitmap, p1) + ; BitmapToCoimage("safeArray", pBitmap, extension, quality) + if (cotype = "safeArray") + return this.put_safeArray(pBitmap, p1, p2) + throw Error("Conversion from bitmap to " cotype " is not supported.") } @@ -637,6 +648,10 @@ class ImagePut { if (cotype = "explorer") return this.set_explorer(pStream, p1) + ; StreamToCoimage("safeArray", pStream) + if (cotype = "safeArray") + return this.set_safeArray(pStream) + throw Error("Conversion from stream to " cotype " is not supported.") } @@ -3203,6 +3218,50 @@ class ImagePut { return wicBitmap } + static set_safeArray(pStream) { + ; Allocate a one-dimensional SAFEARRAY based on the size of the stream. + DllCall("shlwapi\IStream_Size", "ptr", pStream, "uint64*", &size:=0, "HRESULT") + safeArray := ComObjArray(0x11, size) ; VT_ARRAY | VT_UI1 + pvData := NumGet(ComObjValue(safeArray), 8 + A_PtrSize, "ptr") + + ; Copy the stream to the SAFEARRAY. + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") + DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", pvData, "uint", size, "HRESULT") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") + + return safeArray + } + + static put_safeArray(pBitmap, extension := "", quality := "") { + ; Thanks tmplinshi - https://www.autohotkey.com/boards/viewtopic.php?p=354007#p354007 + + ; Create an IStream backed with movable memory. + hData := DllCall("GlobalAlloc", "uint", 0x2, "uptr", 0, "ptr") + DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", True, "ptr*", &pStream:=0, "HRESULT") + + ; Default extension is PNG for small sizes! + (extension == "") && extension := "png" + + ; Save pBitmap to the IStream. + this.select_codec(pBitmap, extension, quality, &pCodec, &ep, &ci, &v) + DllCall("gdiplus\GdipSaveImageToStream", "ptr", pBitmap, "ptr", pStream, "ptr", pCodec, "ptr", IsSet(ep) ? ep : 0) + + ; Get the pointer and size of the IStream's movable memory. + pData := DllCall("GlobalLock", "ptr", hData, "ptr") + size := DllCall("GlobalSize", "ptr", pData, "uptr") + + ; Copy the encoded image to a SAFEARRAY. + safeArray := ComObjArray(0x11, size) ; VT_ARRAY | VT_UI1 + pvData := NumGet(ComObjValue(safeArray), 8 + A_PtrSize, "ptr") + DllCall("RtlMoveMemory", "ptr", pvData, "ptr", pData, "uptr", size) + + ; Release the IStream and call GlobalFree. + DllCall("GlobalUnlock", "ptr", hData) + ObjRelease(pStream) + + return safeArray + } + static select_codec(pBitmap, extension, quality, &pCodec, &ep, &ci, &v) { ; Fill a buffer with the available image codec info. DllCall("gdiplus\GdipGetImageEncodersSize", "uint*", &count:=0, "uint*", &size:=0) From 31dea013e3a723dc0150ffe0cf1b8a895645ff56 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 4 Sep 2022 22:18:50 -0400 Subject: [PATCH 348/492] considering adding formdata... --- ImagePut (for v1).ahk | 6 ++++++ ImagePut.ahk | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index e50fc0bf..eaff676f 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -60,6 +60,12 @@ ImagePutFile(image, filepath := "", quality := "") { return ImagePut("file", image, filepath, quality) } +; Puts the image into a multipart/form-data in binary and returns a SafeArray COM Object. +; content - Content-Type | string -> multipart/form-data; boundary=something +ImagePutFormData(image, content) { ; NOT IMPLEMENTED + return ImagePut("formdata", image, content) +} + ; Puts the image into a device independent bitmap and returns the handle. ; alpha - Alpha Replacement Color | RGB -> 0xFFFFFF ImagePutHBitmap(image, alpha := "") { diff --git a/ImagePut.ahk b/ImagePut.ahk index 08032fa0..4d1cca75 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -60,6 +60,12 @@ ImagePutFile(image, filepath := "", quality := "") { return ImagePut("file", image, filepath, quality) } +; Puts the image into a multipart/form-data in binary and returns a SafeArray COM Object. +; content - Content-Type | string -> multipart/form-data; boundary=something +ImagePutFormData(image, content) { ; NOT IMPLEMENTED + return ImagePut("formdata", image, content) +} + ; Puts the image into a device independent bitmap and returns the handle. ; alpha - Alpha Replacement Color | RGB -> 0xFFFFFF ImagePutHBitmap(image, alpha := "") { From 899484f643ea9aa2a25bbff9193e7469ca8e13e5 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 6 Sep 2022 21:13:27 -0400 Subject: [PATCH 349/492] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3c187dac..910b626b 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ Finally, there are several advanced features. The first is the ability to specif * ImagePut is designed to be fast. * Only functions to and from streams, bitmaps are considered. -* Functions like PNG to hIcon are not considered. +* Specific functions between formats like PNG to hIcon are not considered. * ImagePut should serve as a reference implementation. * Therefore users should be able to copy and paste individual functions. * If you need help extracting a function please ask! From f5f50b9a9556481b8ecc8373e9e4ee2b134d46e8 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 6 Sep 2022 21:24:08 -0400 Subject: [PATCH 350/492] Update README.md --- README.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 910b626b..d7611c38 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,13 @@ # ImagePut -* Standalone library. -* Easily understandable syntax. -* Accepts all [images](https://github.com/iseahound/ImagePut/wiki/Input-Types-&-Output-Functions#input-types), useful for debugging. -* Fast [pixelsearch](https://github.com/iseahound/ImagePut/wiki/PixelSearch-and-ImageSearch#pixelsearch) and imagesearch. -* Highly robust code that has undergone extensive testing. +#### A core library for images in AutoHotkey + +* Screen capture with fast [PixelSearch](https://github.com/iseahound/ImagePut/wiki/PixelSearch-and-ImageSearch#pixelsearch) and ImageSearch +* Decipher over [20+ image types](https://github.com/iseahound/ImagePut/wiki/Quick-Start#accepts) +* Convert from one image format to another +* View and debug your image functions with `ImagePutWindow(image)` +* The magical `image` parameter supports [all image types](https://github.com/iseahound/ImagePut/wiki/Input-Types-&-Output-Functions#input-types) through type inference +* Highly robust code that has undergone extensive testing ## Documentation From 20ece2c6089108e53afe8af758a062bd9053b5a9 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 16 Sep 2022 16:38:47 -0400 Subject: [PATCH 351/492] Interface for FormData (not implemented) --- ImagePut (for v1).ahk | 17 ++++++++++++----- ImagePut.ahk | 16 ++++++++++++---- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index eaff676f..ff35ea0d 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -61,9 +61,9 @@ ImagePutFile(image, filepath := "", quality := "") { } ; Puts the image into a multipart/form-data in binary and returns a SafeArray COM Object. -; content - Content-Type | string -> multipart/form-data; boundary=something -ImagePutFormData(image, content) { ; NOT IMPLEMENTED - return ImagePut("formdata", image, content) +; boundary - Content-Type | string -> multipart/form-data; boundary=something +ImagePutFormData(image, boundary := "--ImagePut abc 321 xyz--") { + return ImagePut("formdata", image, boundary) } ; Puts the image into a device independent bitmap and returns the handle. @@ -193,7 +193,7 @@ class ImagePut { ; #1 - Stream intermediate. if not decode and not crop and not scale and (type ~= "^(?i:clipboard_png|pdf|url|file|stream|RandomAccessStream|hex|base64)$") - and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64|uri|explorer|safeArray)$") + and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64|uri|explorer|safeArray|formData)$") and (p[1] == "") { ; For now, disallow any specification of extensions. ; Convert via stream intermediate. @@ -590,6 +590,10 @@ class ImagePut { if (cotype = "safeArray") return this.put_safeArray(pBitmap, p1, p2) + ; BitmapToCoimage("formData", pBitmap, boundary, extension, quality) + if (cotype = "formData") + return this.put_formData(pBitmap, p1, p2, p3) + throw Exception("Conversion from bitmap to " cotype " is not supported.") } @@ -658,6 +662,10 @@ class ImagePut { if (cotype = "safeArray") return this.set_safeArray(pStream) + ; StreamToCoimage("formData", pStream, boundary) + if (cotype = "formData") + return this.set_formData(pStream, p1) + throw Exception("Conversion from stream to " cotype " is not supported.") } @@ -3686,7 +3694,6 @@ class ImageEqual extends ImagePut { } ; End of ImageEqual class. - ImagePut_dropfiles() { filepath := "" for each, arg in A_Args { diff --git a/ImagePut.ahk b/ImagePut.ahk index 4d1cca75..e3a9f3fc 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -61,9 +61,9 @@ ImagePutFile(image, filepath := "", quality := "") { } ; Puts the image into a multipart/form-data in binary and returns a SafeArray COM Object. -; content - Content-Type | string -> multipart/form-data; boundary=something -ImagePutFormData(image, content) { ; NOT IMPLEMENTED - return ImagePut("formdata", image, content) +; boundary - Content-Type | string -> multipart/form-data; boundary=something +ImagePutFormData(image, boundary := "ImagePut-abcdef") { + return ImagePut("formdata", image, boundary) } ; Puts the image into a device independent bitmap and returns the handle. @@ -193,7 +193,7 @@ class ImagePut { ; #1 - Stream intermediate. if not decode and not crop and not scale and (type ~= "^(?i:clipboard_png|pdf|url|file|stream|RandomAccessStream|hex|base64)$") - and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64|uri|explorer|safeArray)$") + and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64|uri|explorer|safeArray|formData)$") and (!p.Has(1) || p[1] == "") { ; For now, disallow any specification of extensions. ; Convert via stream intermediate. @@ -590,6 +590,10 @@ class ImagePut { if (cotype = "safeArray") return this.put_safeArray(pBitmap, p1, p2) + ; BitmapToCoimage("formData", pBitmap, boundary, extension, quality) + if (cotype = "formData") + return this.put_formData(pBitmap, p1, p2, p3) + throw Error("Conversion from bitmap to " cotype " is not supported.") } @@ -658,6 +662,10 @@ class ImagePut { if (cotype = "safeArray") return this.set_safeArray(pStream) + ; StreamToCoimage("formData", pStream, boundary) + if (cotype = "formData") + return this.set_formData(pStream, p1) + throw Error("Conversion from stream to " cotype " is not supported.") } From 718d64463768ab8b84140c0aa64ae626743da90c Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 4 Oct 2022 20:18:57 -0400 Subject: [PATCH 352/492] Modify WindowClass to allow optional double clicks --- ImagePut (for v1).ahk | 4 ++-- ImagePut.ahk | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index ff35ea0d..379274bb 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2518,7 +2518,7 @@ class ImagePut { return hwnd } - WindowClass() { + WindowClass(style := 0) { ; The window class shares the name of this class. cls := this.__class VarSetCapacity(wc, size := A_PtrSize = 4 ? 48:80) ; sizeof(WNDCLASSEX) = 48, 80 @@ -2537,7 +2537,7 @@ class ImagePut { ; struct tagWNDCLASSEXW - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexw _ := (A_PtrSize = 4) NumPut( size, wc, 0, "uint") ; cbSize - NumPut( 0x8, wc, 4, "uint") ; style + NumPut( style, wc, 4, "uint") ; style NumPut( pWndProc, wc, 8, "ptr") ; lpfnWndProc NumPut( 0, wc, _ ? 12:16, "int") ; cbClsExtra NumPut( 40, wc, _ ? 16:20, "int") ; cbWndExtra diff --git a/ImagePut.ahk b/ImagePut.ahk index e3a9f3fc..a36df784 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2518,7 +2518,7 @@ class ImagePut { return hwnd } - static WindowClass() { + static WindowClass(style := 0) { ; The window class shares the name of this class. cls := this.prototype.__class wc := Buffer(A_PtrSize = 4 ? 48:80) ; sizeof(WNDCLASSEX) = 48, 80 @@ -2537,7 +2537,7 @@ class ImagePut { ; struct tagWNDCLASSEXW - https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexw _ := (A_PtrSize = 4) NumPut( "uint", wc.size, wc, 0) ; cbSize - NumPut( "uint", 0x8, wc, 4) ; style + NumPut( "uint", style, wc, 4) ; style NumPut( "ptr", pWndProc, wc, 8) ; lpfnWndProc NumPut( "int", 0, wc, _ ? 12:16) ; cbClsExtra NumPut( "int", 40, wc, _ ? 16:20) ; cbWndExtra From b638ac5aa55bb28113522e6ed28858fc278bb5ce Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 17 Oct 2022 16:54:15 -0400 Subject: [PATCH 353/492] Enumerate over colors with a for loop --- ImagePut (for v1).ahk | 107 ++++++++++++++++++++++++++++++++++++++++++ ImagePut.ahk | 107 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 214 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 379274bb..3dc3a98d 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1983,6 +1983,113 @@ class ImagePut { return color } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Crop(x, y, w, h) { DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", this.pBitmap, "int*", format:=0) DllCall("gdiplus\GdipCloneBitmapAreaI", "int", x, "int", y, "int", w, "int", h, "int", format, "ptr", this.pBitmap, "ptr*", pBitmap:=0) diff --git a/ImagePut.ahk b/ImagePut.ahk index a36df784..d688f72a 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1980,8 +1980,115 @@ class ImagePut { value) } + __Enum(n) { + + start := 0 + end := this.size + + switch n { + case 1: + enum1(&c) { + + if start == end + return False + + ; yield statements + c := Format("0x{:X}", NumGet(this, start, "uint")) + + ; do block + start += 4 + + ; continue? + return start <= end + } + return enum1 + + case 2: + enum2(&i, &c) { + + if start == end + return False + + ; yield statements + i := start // 4 + c := Format("0x{:X}", NumGet(this, start, "uint")) + + ; do block + start += 4 + + ; continue? + return start <= end + } + return enum2 + + case 3: + enum3(&x, &y, &c) { + + if start == end + return False + + ; yield statements + i := start // 4 + x := mod(i, this.width) + y := i // this.width + c := Format("0x{:X}", NumGet(this, start, "uint")) + + ; do block + start += 4 + + ; continue? + return start <= end + } + return enum3 + + case 6: + enum6(&x, &y, &c, &r, &g, &b) { + + if start == end + return False + + ; yield statements + i := start // 4 + x := mod(i, this.width) + y := i // this.width + c := Format("0x{:X}", NumGet(this, start, "uint")) + r := c >> 16 & 0xFF + g := c >> 8 & 0xFF + b := c & 0xFF + + ; do block + start += 4 + + ; continue? + return start <= end + } + return enum6 + case 7: + enum7(&x, &y, &c, &r, &g, &b, &a) { + if start == end + return False + + ; yield statements + i := start // 4 + x := mod(i, this.width) + y := i // this.width + c := Format("0x{:X}", NumGet(this, start, "uint")) + r := c >> 16 & 0xFF + g := c >> 8 & 0xFF + b := c & 0xFF + a := c >> 24 & 0xFF + + ; do block + start += 4 + + ; continue? + return start <= end + } + return enum7 + } + } Crop(x, y, w, h) { DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", this.pBitmap, "int*", &format:=0) From 856f26e91a7a995b1b656cc504a19d2bab33ab42 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 4 Nov 2022 22:53:59 -0400 Subject: [PATCH 354/492] Fix crop() for BitmapBuffer --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 3dc3a98d..87144fff 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2093,7 +2093,7 @@ class ImagePut { Crop(x, y, w, h) { DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", this.pBitmap, "int*", format:=0) DllCall("gdiplus\GdipCloneBitmapAreaI", "int", x, "int", y, "int", w, "int", h, "int", format, "ptr", this.pBitmap, "ptr*", pBitmap:=0) - return new ImagePut.BitmapBuffer(pBitmap) + return new ImagePut.put_buffer(pBitmap) } Show(window_border := False, title := "", pos := "", style := "", styleEx := "", parent := "") { diff --git a/ImagePut.ahk b/ImagePut.ahk index d688f72a..2d7745d4 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2093,7 +2093,7 @@ class ImagePut { Crop(x, y, w, h) { DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", this.pBitmap, "int*", &format:=0) DllCall("gdiplus\GdipCloneBitmapAreaI", "int", x, "int", y, "int", w, "int", h, "int", format, "ptr", this.pBitmap, "ptr*", &pBitmap:=0) - return ImagePut.BitmapBuffer(pBitmap) + return ImagePut.put_buffer(pBitmap) } Show(window_border := False, title := "", pos := "", style := "", styleEx := "", parent := "") { From 55abe4bd0cbe9b394ea5a39963d23e67e8a842d7 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 4 Nov 2022 23:11:27 -0400 Subject: [PATCH 355/492] Check for image.prototype before image.prototype.__class --- ImagePut.ahk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index 2d7745d4..4d9257e5 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -304,7 +304,7 @@ class ImagePut { throw Error("Image data is an empty string.") if IsObject(image) { - if (image.prototype.HasOwnProp("__class") && image.prototype.__class == "ClipboardAll" + if (image.HasOwnProp("prototype") && image.prototype.HasOwnProp("__class") && image.prototype.__class == "ClipboardAll" || image.base.HasOwnProp("__class") && image.base.__class == "ClipboardAll") { ; A "clipboard_png" is a pointer to a PNG stream saved as the "png" clipboard format. From ba88b4e0ce4442bb70804eebe8486cb3abb3f188 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 4 Nov 2022 23:50:34 -0400 Subject: [PATCH 356/492] ImageSearch now searches more than one row of pixels --- ImagePut (for v1).ahk | 14 +++++++------- ImagePut.ahk | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 87144fff..8ae6b7fb 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2298,15 +2298,15 @@ class ImagePut { } ImageSearch(image) { - ; C source code - https://godbolt.org/z/q1rxvx38Y + ; C source code - https://godbolt.org/z/7b4b734dW static code := 0 (code) || code := this.Base64Put((A_PtrSize == 4) - ? "VYnlV1ZTg+wUi1UYi3UUi0UQi30MjTSWi00MiXXoi3UcjRyFAAAAACnXK0UcD6/LA00IiX3kweYCiUXgiXXsiU3wi00IO03wc0yL" - . "RRSLADkBdT6JyCtFCDHSwfgC93UMOVXkfiw5ReB+J4tFFInKMf87fRx0IztF6HMOizI5MHUQg8IEg8AE6+0B2gNF7Efr4IPBBOuv" - . "i03wg8QUichbXl9dww==" - : "QVdBVkFVQVRVV1ZTi0QkaIt0JHBIifdIweYCSYnLidFEicNBD6/QQYnNSMHjAk2J2kEpxUEp+EmNLJOJwk2NJJFJOepzVkGLAUE5" - . "AnVITInQMdJMKdhIwfgC9/FBOdV+NUE5wH4wTInSTInIRTH2QTn+dCtMOeBzEkSLOkQ5OHUVSIPCBEiDwATr6UgB2kgB8EH/xuvZ" - . "SYPCBOulSYnqTInQW15fXUFcQV1BXkFfww==") + ? "VYnlV1ZTg+wUi0UMi1UYi00IjTyFAAAAAItFECtFHA+vxwNFCIlF6ItFDCnQiUXkjQSVAAAAAIlF7ItF6DnBc1iLRRSLADkBdUqJ" + . "yCtFCDHSwfgC93UMOVXkfDgx0otFFInLiVXwi3XwO3UcdCuLVeyJ3gHCiVXgi1XgOdBzDosWORB1D4PABIPGBOvr/0XwAfvr0oPB" + . "BOuhg8QUichbXl9dww==" + : "QVZBVUFUVVdWU4tcJGiLRCRgQSnYiddJictBidJED6/CKcdKjTSBTI0EhQAAAABIOfFzVUGLATkBdUhIicgx0kwp2EjB+AJB9/I5" + . "13w1TInIMe0x0jnadDBBiexOjSwATo0koUw56HMTRYs0JEQ5MHURSIPABEmDxATr6P/CRAHV69JIg8EE66ZIichbXl9dQVxBXUFe" + . "ww==") ; Check for a .pBitmap property if !(IsObject(image) && ObjHasKey(image, "pBitmap")) diff --git a/ImagePut.ahk b/ImagePut.ahk index 4d9257e5..f769b2ff 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2298,15 +2298,15 @@ class ImagePut { } ImageSearch(image) { - ; C source code - https://godbolt.org/z/q1rxvx38Y + ; C source code - https://godbolt.org/z/7b4b734dW static code := 0 (code) || code := this.Base64Put((A_PtrSize == 4) - ? "VYnlV1ZTg+wUi1UYi3UUi0UQi30MjTSWi00MiXXoi3UcjRyFAAAAACnXK0UcD6/LA00IiX3kweYCiUXgiXXsiU3wi00IO03wc0yL" - . "RRSLADkBdT6JyCtFCDHSwfgC93UMOVXkfiw5ReB+J4tFFInKMf87fRx0IztF6HMOizI5MHUQg8IEg8AE6+0B2gNF7Efr4IPBBOuv" - . "i03wg8QUichbXl9dww==" - : "QVdBVkFVQVRVV1ZTi0QkaIt0JHBIifdIweYCSYnLidFEicNBD6/QQYnNSMHjAk2J2kEpxUEp+EmNLJOJwk2NJJFJOepzVkGLAUE5" - . "AnVITInQMdJMKdhIwfgC9/FBOdV+NUE5wH4wTInSTInIRTH2QTn+dCtMOeBzEkSLOkQ5OHUVSIPCBEiDwATr6UgB2kgB8EH/xuvZ" - . "SYPCBOulSYnqTInQW15fXUFcQV1BXkFfww==") + ? "VYnlV1ZTg+wUi0UMi1UYi00IjTyFAAAAAItFECtFHA+vxwNFCIlF6ItFDCnQiUXkjQSVAAAAAIlF7ItF6DnBc1iLRRSLADkBdUqJ" + . "yCtFCDHSwfgC93UMOVXkfDgx0otFFInLiVXwi3XwO3UcdCuLVeyJ3gHCiVXgi1XgOdBzDosWORB1D4PABIPGBOvr/0XwAfvr0oPB" + . "BOuhg8QUichbXl9dww==" + : "QVZBVUFUVVdWU4tcJGiLRCRgQSnYiddJictBidJED6/CKcdKjTSBTI0EhQAAAABIOfFzVUGLATkBdUhIicgx0kwp2EjB+AJB9/I5" + . "13w1TInIMe0x0jnadDBBiexOjSwATo0koUw56HMTRYs0JEQ5MHURSIPABEmDxATr6P/CRAHV69JIg8EE66ZIichbXl9dQVxBXUFe" + . "ww==") ; Check for a .pBitmap property if !(IsObject(image) && ObjHasOwnProp(image, "pBitmap")) From 05a84992897f2a0e2514c03b4e6717023d03ce97 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 4 Nov 2022 23:52:00 -0400 Subject: [PATCH 357/492] C source files --- source/imagesearch.c | 73 +++++++++++++++++++++-------------------- source/some_other.c | 14 ++++++++ source/some_xmm_tests.c | 11 +++++++ 3 files changed, 63 insertions(+), 35 deletions(-) create mode 100644 source/some_other.c create mode 100644 source/some_xmm_tests.c diff --git a/source/imagesearch.c b/source/imagesearch.c index 24d7f51c..215f6dac 100644 --- a/source/imagesearch.c +++ b/source/imagesearch.c @@ -1,46 +1,49 @@ -unsigned int * imagesearch(unsigned int * Scan0, unsigned int width, unsigned int height, unsigned int * image, unsigned int w, unsigned int h) { - unsigned int * start = Scan0; - unsigned int * end = Scan0 + width * height; +unsigned int * imagesearch(unsigned int * start, unsigned int width, unsigned int height, unsigned int * s, unsigned int w, unsigned int h) { + // width, height, start, current, end refer to the haystack (main image) + // x, y, w, h, s, c, e refer to the needle (search image) + + unsigned int * current = start; + unsigned int * end = start + width * (height - h); // Remaining area must be greater than search height + + int range_x = width - w; + int range_y = height - h; // optimized away + + int x, y, offset; + unsigned int * c; + unsigned int * e; + unsigned int * p; // Start off searching with pointers. - while (start < end) { - - int x, y, offset; - int max_w = width - w; - int max_h = height - h; - unsigned int * s; - unsigned int * e; - unsigned int * current; - - // Dereference pointers to check first pixel of subimage. - if (*start == *image) { - // Convert pointer to (x, y). - offset = start - Scan0; - x = offset % width; - y = offset / width; + while (current < end) { - // Subimage loop. - current = start; - s = image; - e = image + w; + // Check if the current pixel matches the first pixel of subimage. + if (*current == *s) { + + // Convert current pointer to (x, y). + offset = current - start; + x = offset % width; + y = offset / width; // optimized away // Check if (x, y) exceeds bounds. - if (x < max_w && y < max_h) { - for (int i = 0; i < h; i++) { - while (s < e) { - if (*s != *current) - goto next; - current++; - s++; - } - current += height; - s += h; + if (x > range_x) // range_y check is done above + goto next; + + // Subimage loop. + c = s; + for (int i = 0; i < h; i++) { + p = current + width * i; + e = c + w; + while (c < e) { + if (*c != *p) + goto next; + c++; // Here simply incrementing will interate the entire image + p++; // Will be reset each run } - return start; } + return current; } next: - start++; + current++; } - return start; // start == end if no match. + return current; // current == end } \ No newline at end of file diff --git a/source/some_other.c b/source/some_other.c new file mode 100644 index 00000000..e3109508 --- /dev/null +++ b/source/some_other.c @@ -0,0 +1,14 @@ +#include +#include +#include +#include + +void main() { + int32_t __attribute__ ((aligned(16))) vector1[4] = { 1, 2, 3, 4 }; + int32_t __attribute__ ((aligned(16))) vector2[4] = { 1, 2, 2, 2 }; + int32_t __attribute__ ((aligned(16))) result[4]; + + __m128i v1 = _mm_load_si128((__m128i *)vector1); + __m128i v2 = _mm_load_si128((__m128i *)vector2); + __m128i vcmp = _mm_cmpeq_epi32(v1, v2); +} \ No newline at end of file diff --git a/source/some_xmm_tests.c b/source/some_xmm_tests.c new file mode 100644 index 00000000..ddff9fbd --- /dev/null +++ b/source/some_xmm_tests.c @@ -0,0 +1,11 @@ +#include +#include +#include + +int main(unsigned int * start) { + __m128i input = _mm_loadu_si128(*start); + const __m128i populated_0th_byte = _mm_shuffle_epi8(input, _mm_setzero_si128()); + const __m128i eq = _mm_cmpeq_epi8(input, populated_0th_byte); + + return (_mm_movemask_epi8(eq) == 0xffff); +} \ No newline at end of file From 32bbee3f8e2ecfe2afb45784d65c2bba90bd31c0 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 5 Nov 2022 10:23:52 -0400 Subject: [PATCH 358/492] C source files --- source/imagesearch.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/source/imagesearch.c b/source/imagesearch.c index 215f6dac..dcaffca1 100644 --- a/source/imagesearch.c +++ b/source/imagesearch.c @@ -17,7 +17,7 @@ unsigned int * imagesearch(unsigned int * start, unsigned int width, unsigned in while (current < end) { // Check if the current pixel matches the first pixel of subimage. - if (*current == *s) { + if (*current == *s || *((unsigned char *) s + 3) == 0) { // just continue if search image is transparent // Convert current pointer to (x, y). offset = current - start; @@ -34,8 +34,10 @@ unsigned int * imagesearch(unsigned int * start, unsigned int width, unsigned in p = current + width * i; e = c + w; while (c < e) { - if (*c != *p) - goto next; + if (*((unsigned char *) c + 3)) { // skip transparent pixels in search image + if (*c != *p) + goto next; + } c++; // Here simply incrementing will interate the entire image p++; // Will be reset each run } @@ -45,5 +47,5 @@ unsigned int * imagesearch(unsigned int * start, unsigned int width, unsigned in next: current++; } - return current; // current == end + return start + width * height; // real end } \ No newline at end of file From 566d17161484f225b9eb5bd5caf7d4ccab8b8dc7 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 5 Nov 2022 10:24:26 -0400 Subject: [PATCH 359/492] ImageSearch works with Transcolor --- ImagePut (for v1).ahk | 14 +++++++------- ImagePut.ahk | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 8ae6b7fb..5806fe72 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2298,15 +2298,15 @@ class ImagePut { } ImageSearch(image) { - ; C source code - https://godbolt.org/z/7b4b734dW + ; C source code - https://godbolt.org/z/qPodGdP1d static code := 0 (code) || code := this.Base64Put((A_PtrSize == 4) - ? "VYnlV1ZTg+wUi0UMi1UYi00IjTyFAAAAAItFECtFHA+vxwNFCIlF6ItFDCnQiUXkjQSVAAAAAIlF7ItF6DnBc1iLRRSLADkBdUqJ" - . "yCtFCDHSwfgC93UMOVXkfDgx0otFFInLiVXwi3XwO3UcdCuLVeyJ3gHCiVXgi1XgOdBzDosWORB1D4PABIPGBOvr/0XwAfvr0oPB" - . "BOuhg8QUichbXl9dww==" - : "QVZBVUFUVVdWU4tcJGiLRCRgQSnYiddJictBidJED6/CKcdKjTSBTI0EhQAAAABIOfFzVUGLATkBdUhIicgx0kwp2EjB+AJB9/I5" - . "13w1TInIMe0x0jnadDBBiexOjSwATo0koUw56HMTRYs0JEQ5MHURSIPABEmDxATr6P/CRAHV69JIg8EE66ZIichbXl9dQVxBXUFe" - . "ww==") + ? "VYnlV1ZTg+wUi0UMi1UYi00IjTyFAAAAAItFECtFHA+vxwNFCIlF6ItFDCnQiUXkjQSVAAAAAIlF7ItF6DnBc2eLRRSLADkBdAmL" + . "RRSAeAMAdVCJyCtFCDHSwfgC93UMOVXkfD4x0otFFInLiVXwi3XwO3UcdDyLVeyJ3gHCiVXgi1XgOdBzFIB4AwB0BosWORB1D4PA" + . "BIPGBOvl/0XwAfvrzIPBBOuSi0UQD6/HA0UIicGDxBSJyFteX13D" + : "QVdBVkFVQVRVV1ZTi1wkcItEJGhIjSyFAAAAAEGJ0kSJwkmJyynaRInXQQ+v0inHSI00kUg58XNjQYsBOQF0B0GAeQMAdU9Iicgx" + . "0kwp2EjB+AJB9/I513w8TInIRTHkMdI52nQ+RYnlTI00KE6NLKlMOfBzGYB4AwB0CUWLfQBEOTh1EUiDwARJg8UE6+L/wkUB1OvM" + . "SIPBBOuYRQ+vwkuNDINIichbXl9dQVxBXUFeQV/D") ; Check for a .pBitmap property if !(IsObject(image) && ObjHasKey(image, "pBitmap")) diff --git a/ImagePut.ahk b/ImagePut.ahk index f769b2ff..250ff868 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2298,15 +2298,15 @@ class ImagePut { } ImageSearch(image) { - ; C source code - https://godbolt.org/z/7b4b734dW + ; C source code - https://godbolt.org/z/qPodGdP1d static code := 0 (code) || code := this.Base64Put((A_PtrSize == 4) - ? "VYnlV1ZTg+wUi0UMi1UYi00IjTyFAAAAAItFECtFHA+vxwNFCIlF6ItFDCnQiUXkjQSVAAAAAIlF7ItF6DnBc1iLRRSLADkBdUqJ" - . "yCtFCDHSwfgC93UMOVXkfDgx0otFFInLiVXwi3XwO3UcdCuLVeyJ3gHCiVXgi1XgOdBzDosWORB1D4PABIPGBOvr/0XwAfvr0oPB" - . "BOuhg8QUichbXl9dww==" - : "QVZBVUFUVVdWU4tcJGiLRCRgQSnYiddJictBidJED6/CKcdKjTSBTI0EhQAAAABIOfFzVUGLATkBdUhIicgx0kwp2EjB+AJB9/I5" - . "13w1TInIMe0x0jnadDBBiexOjSwATo0koUw56HMTRYs0JEQ5MHURSIPABEmDxATr6P/CRAHV69JIg8EE66ZIichbXl9dQVxBXUFe" - . "ww==") + ? "VYnlV1ZTg+wUi0UMi1UYi00IjTyFAAAAAItFECtFHA+vxwNFCIlF6ItFDCnQiUXkjQSVAAAAAIlF7ItF6DnBc2eLRRSLADkBdAmL" + . "RRSAeAMAdVCJyCtFCDHSwfgC93UMOVXkfD4x0otFFInLiVXwi3XwO3UcdDyLVeyJ3gHCiVXgi1XgOdBzFIB4AwB0BosWORB1D4PA" + . "BIPGBOvl/0XwAfvrzIPBBOuSi0UQD6/HA0UIicGDxBSJyFteX13D" + : "QVdBVkFVQVRVV1ZTi1wkcItEJGhIjSyFAAAAAEGJ0kSJwkmJyynaRInXQQ+v0inHSI00kUg58XNjQYsBOQF0B0GAeQMAdU9Iicgx" + . "0kwp2EjB+AJB9/I513w8TInIRTHkMdI52nQ+RYnlTI00KE6NLKlMOfBzGYB4AwB0CUWLfQBEOTh1EUiDwARJg8UE6+L/wkUB1OvM" + . "SIPBBOuYRQ+vwkuNDINIichbXl9dQVxBXUFeQV/D") ; Check for a .pBitmap property if !(IsObject(image) && ObjHasOwnProp(image, "pBitmap")) From 1009deb8141dda10f97ac14afcae79eeb5e60e1f Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 6 Nov 2022 00:41:00 -0400 Subject: [PATCH 360/492] remove unneeded named function --- ImagePut (for v1).ahk | 2 -- ImagePut.ahk | 6 ++---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 5806fe72..d73f1e9f 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2135,8 +2135,6 @@ class ImagePut { NumPut( 0, bm, 42, "int") ; biYPelsPerMeter NumPut( 0, bm, 46, "uint") ; biClrUsed NumPut( 0, bm, 50, "uint") ; biClrImportant - - } loop diff --git a/ImagePut.ahk b/ImagePut.ahk index 250ff868..edf67019 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2113,8 +2113,8 @@ class ImagePut { return ImagePut.put_file(this.pBitmap, filepath, quality) ; Save header info. - static bm := CreateBitmapHeader() - CreateBitmapHeader() { + static bm := 0 + if !bm { bm := Buffer(54) StrPut("BM", bm, "CP0") ; identifier @@ -2135,8 +2135,6 @@ class ImagePut { NumPut( "int", 0, bm, 42) ; biYPelsPerMeter NumPut( "uint", 0, bm, 46) ; biClrUsed NumPut( "uint", 0, bm, 50) ; biClrImportant - - return bm } loop From ec058ddfce75e1fa0048250d1857b5e3a749b5ae Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 6 Nov 2022 00:41:52 -0400 Subject: [PATCH 361/492] v1.9 --- ImagePut (for v1).ahk | 4 ++-- ImagePut.ahk | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index d73f1e9f..bbea75bb 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2,8 +2,8 @@ ; License: MIT License ; Author: Edison Hua (iseahound) ; Github: https://github.com/iseahound/ImagePut -; Date: 2022-06-17 -; Version: 1.8.1 +; Date: 2022-11-06 +; Version: 1.9 #Requires AutoHotkey v1.1.33+ diff --git a/ImagePut.ahk b/ImagePut.ahk index edf67019..be4a97af 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2,8 +2,8 @@ ; License: MIT License ; Author: Edison Hua (iseahound) ; Github: https://github.com/iseahound/ImagePut -; Date: 2022-06-17 -; Version: 1.8.1 +; Date: 2022-11-06 +; Version: 1.9 #Requires AutoHotkey v2.0-beta.3+ From 5d84c604cda2b575a99c21a7038e98b99eb51d96 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 17 Dec 2022 00:25:38 -0500 Subject: [PATCH 362/492] Add PixelSearchAll --- ImagePut.ahk | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/ImagePut.ahk b/ImagePut.ahk index be4a97af..84773bcb 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2295,6 +2295,42 @@ class ImagePut { return [mod(offset, this.width), offset // this.width] } + PixelSearchAll(color) { + ; C source code - https://godbolt.org/z/zPY1qMvYe + static PixelSearch3 := 0 + (PixelSearch3) || PixelSearch3 := this.Base64Put((A_PtrSize == 4) + ? "VYnli1UMi00Qi0UIOdBzCTkIdAeDwATr84nQXcM=" + : "McBEi1QkKE05yHMYRTkQdQ050HMHQYnDTokE2f/ASYPABOvjww==") + + ; Lift color to 32-bits if first 8 bits are zero. + (color >> 24) || color |= 0xFF000000 + + ; PixelSearchAll, single color, no variation + capacity := 256 + result := Buffer(A_PtrSize * capacity) + count := DllCall(PixelSearch3, "ptr", result, "uint", capacity, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "uint") + + ; If the default 256 results is exceeded, run the function again. + if (count > capacity) { + result.size := A_PtrSize * count + count := DllCall(PixelSearch3, "ptr", result, "uint", count, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "uint") + } + + ; Check if color is found. + if (count = 0) + return False + + ; Create an array of [x, y] coordinates. + xys := [] + loop count { + byte := NumGet(result, A_Index-1, "ptr") + offset := (byte - this.ptr) // 4 + xy := [mod(offset, this.width), offset // this.width] + xys.push(xy) + } + return xys + } + ImageSearch(image) { ; C source code - https://godbolt.org/z/qPodGdP1d static code := 0 From bd1116f211a9f8e65109b98831ad80f97b64e68b Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 17 Dec 2022 11:29:16 -0500 Subject: [PATCH 363/492] ImageSearchAll --- ImagePut.ahk | 44 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index 84773bcb..be35d532 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2316,14 +2316,14 @@ class ImagePut { count := DllCall(PixelSearch3, "ptr", result, "uint", count, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "uint") } - ; Check if color is found. + ; Check if any matches are found. if (count = 0) return False ; Create an array of [x, y] coordinates. xys := [] loop count { - byte := NumGet(result, A_Index-1, "ptr") + byte := NumGet(result, A_PtrSize*(A_Index-1), "ptr") offset := (byte - this.ptr) // 4 xy := [mod(offset, this.width), offset // this.width] xys.push(xy) @@ -2358,6 +2358,46 @@ class ImagePut { offset := (byte - this.ptr) // 4 return [mod(offset, this.width), offset // this.width] } + + ImageSearchAll(image) { + ; C source code - https://godbolt.org/z/qPodGdP1d + static code := 0 + (code) || code := this.Base64Put((A_PtrSize == 4) + ? "VYnlV1ZTg+wUi0UMi1UYi00IjTyFAAAAAItFECtFHA+vxwNFCIlF6ItFDCnQiUXkjQSVAAAAAIlF7ItF6DnBc2eLRRSLADkBdAmL" + . "RRSAeAMAdVCJyCtFCDHSwfgC93UMOVXkfD4x0otFFInLiVXwi3XwO3UcdDyLVeyJ3gHCiVXgi1XgOdBzFIB4AwB0BosWORB1D4PA" + . "BIPGBOvl/0XwAfvrzIPBBOuSi0UQD6/HA0UIicGDxBSJyFteX13D" + : "QVdBVkFVQVRVV1ZTSIPsGEUx20SLpCSYAAAAi4QkgAAAAESLlCSQAAAASIu8JIgAAABEKeBBD6/BSInLidZMicFNjSyARInIRCnQiUQkDEqNBJUAAAAASIkEJEw56XN0iwc5AXQGgH8DAHViSInIMdJMKcBIwfgCQffxOVQkDHxNSIn4Me0x0kQ54nQyTIs8JEGJ7k6NNLFJAcdMOfhzGIB4AwB0CEWLFkQ5EHUgSIPABEmDxgTr4//CRAHN68lBOfNzB0SJ2EiJDMNB/8NIg8EE64dEidhIg8QYW15fXUFcQV1BXkFfww==" +) + + ; Search for the address of the first matching image. + capacity := 256 + result := Buffer(A_PtrSize * capacity) + count := DllCall(code, "ptr", result, "uint", capacity + , "ptr", this.ptr, "uint", this.width, "uint", this.height + , "ptr", image.ptr, "uint", image.width, "uint", image.height, "uint") + + ; If more than 256 results, run the function with the true capacity. + if (count > capacity) { + result.size := A_PtrSize * count + count := DllCall(code, "ptr", result, "uint", capacity + , "ptr", this.ptr, "uint", this.width, "uint", this.height + , "ptr", image.ptr, "uint", image.width, "uint", image.height, "uint") + } + + ; Check if any matches are found. + if (count = 0) + return False + + ; Create an array of [x, y] coordinates. + xys := [] + loop count { + byte := NumGet(result, A_PtrSize*(A_Index-1), "ptr") + offset := (byte - this.ptr) // 4 + xy := [mod(offset, this.width), offset // this.width] + xys.push(xy) + } + return xys + } } static put_screenshot(pBitmap, screenshot := "", alpha := "") { From 6ade3ffa37ad70abd67db98249d8453279389d0f Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 19 Dec 2022 19:21:09 -0500 Subject: [PATCH 364/492] Transcolor automatically selects the top-left color --- ImagePut (for v1).ahk | 5 ++++- ImagePut.ahk | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index bbea75bb..346268ff 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2223,13 +2223,16 @@ class ImagePut { DllCall(code, "ptr", this.ptr, "ptr", this.ptr + this.size, "uchar", alpha) } - TransColor(color := 0xFFFFFF, alpha := 0x00) { + TransColor(color := "sentinel", alpha := 0x00) { ; C source code - https://godbolt.org/z/z3a8WcM5M static code := 0 (code) || code := this.Base64Put((A_PtrSize == 4) ? "VYnli0UIilUUO0UMcxWLTRAzCIHh////AHUDiFADg8AE6+Zdww==" : "SDnRcxaLAUQxwKn///8AdQREiEkDSIPBBOvlww==") + ; Use top-left pixel as default. + color == "sentinel" && color := NumGet(this.ptr, "uint") + ; Sets the alpha value of a specified RGB color. DllCall(code, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "uchar", alpha) } diff --git a/ImagePut.ahk b/ImagePut.ahk index be35d532..75a67134 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2223,13 +2223,16 @@ class ImagePut { DllCall(code, "ptr", this.ptr, "ptr", this.ptr + this.size, "uchar", alpha) } - TransColor(color := 0xFFFFFF, alpha := 0x00) { + TransColor(color := "sentinel", alpha := 0x00) { ; C source code - https://godbolt.org/z/z3a8WcM5M static code := 0 (code) || code := this.Base64Put((A_PtrSize == 4) ? "VYnli0UIilUUO0UMcxWLTRAzCIHh////AHUDiFADg8AE6+Zdww==" : "SDnRcxaLAUQxwKn///8AdQREiEkDSIPBBOvlww==") + ; Use top-left pixel as default. + color == "sentinel" && color := NumGet(this.ptr, "uint") + ; Sets the alpha value of a specified RGB color. DllCall(code, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "uchar", alpha) } From 109d08b503e51aa53d590153e36d10bdd6f86b5b Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 19 Dec 2022 19:24:00 -0500 Subject: [PATCH 365/492] Colorkey selects the top-left color as default --- ImagePut (for v1).ahk | 5 ++++- ImagePut.ahk | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 346268ff..10920cee 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2201,13 +2201,16 @@ class ImagePut { return cpuid } - ColorKey(key := 0xFFFFFFFF, value := 0x00000000) { + ColorKey(key := "sentinel", value := 0x00000000) { ; C source code - https://godbolt.org/z/eaG9fax9v static code := 0 (code) || code := this.Base64Put((A_PtrSize == 4) ? "VYnli0UIi1UQi00UO0UMcws5EHUCiQiDwATr8F3D" : "SDnRcw5EOQF1A0SJCUiDwQTr7cM=") + ; Use top-left pixel as default. + key == "sentinel" && key := NumGet(this.ptr, "uint") + ; Replaces one ARGB color with another. DllCall(code, "ptr", this.ptr, "uint", this.ptr + this.size, "uint", key, "uint", value) } diff --git a/ImagePut.ahk b/ImagePut.ahk index 75a67134..4bcd2605 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2201,13 +2201,16 @@ class ImagePut { return cpuid } - ColorKey(key := 0xFFFFFFFF, value := 0x00000000) { + ColorKey(key := "sentinel", value := 0x00000000) { ; C source code - https://godbolt.org/z/eaG9fax9v static code := 0 (code) || code := this.Base64Put((A_PtrSize == 4) ? "VYnli0UIi1UQi00UO0UMcws5EHUCiQiDwATr8F3D" : "SDnRcw5EOQF1A0SJCUiDwQTr7cM=") + ; Use top-left pixel as default. + key == "sentinel" && key := NumGet(this.ptr, "uint") + ; Replaces one ARGB color with another. DllCall(code, "ptr", this.ptr, "uint", this.ptr + this.size, "uint", key, "uint", value) } From ba5add747677b71600e770f67b2fac3cde758372 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 19 Dec 2022 19:27:20 -0500 Subject: [PATCH 366/492] comment wording --- ImagePut (for v1).ahk | 4 ++-- ImagePut.ahk | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 10920cee..e7d01ff1 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2208,7 +2208,7 @@ class ImagePut { ? "VYnli0UIi1UQi00UO0UMcws5EHUCiQiDwATr8F3D" : "SDnRcw5EOQF1A0SJCUiDwQTr7cM=") - ; Use top-left pixel as default. + ; Select top-left pixel as default. key == "sentinel" && key := NumGet(this.ptr, "uint") ; Replaces one ARGB color with another. @@ -2233,7 +2233,7 @@ class ImagePut { ? "VYnli0UIilUUO0UMcxWLTRAzCIHh////AHUDiFADg8AE6+Zdww==" : "SDnRcxaLAUQxwKn///8AdQREiEkDSIPBBOvlww==") - ; Use top-left pixel as default. + ; Select top-left pixel as default. color == "sentinel" && color := NumGet(this.ptr, "uint") ; Sets the alpha value of a specified RGB color. diff --git a/ImagePut.ahk b/ImagePut.ahk index 4bcd2605..ba019b45 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2208,7 +2208,7 @@ class ImagePut { ? "VYnli0UIi1UQi00UO0UMcws5EHUCiQiDwATr8F3D" : "SDnRcw5EOQF1A0SJCUiDwQTr7cM=") - ; Use top-left pixel as default. + ; Select top-left pixel as default. key == "sentinel" && key := NumGet(this.ptr, "uint") ; Replaces one ARGB color with another. @@ -2233,7 +2233,7 @@ class ImagePut { ? "VYnli0UIilUUO0UMcxWLTRAzCIHh////AHUDiFADg8AE6+Zdww==" : "SDnRcxaLAUQxwKn///8AdQREiEkDSIPBBOvlww==") - ; Use top-left pixel as default. + ; Select top-left pixel as default. color == "sentinel" && color := NumGet(this.ptr, "uint") ; Sets the alpha value of a specified RGB color. From 279a99540f3022b67f42bebec9ad1a8d5b641fd3 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 19 Dec 2022 19:35:20 -0500 Subject: [PATCH 367/492] Fix parenthesis --- ImagePut (for v1).ahk | 40 ++++++++++++++++++++++++++++++++++++++-- ImagePut.ahk | 4 ++-- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index e7d01ff1..61a2bf39 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2209,7 +2209,7 @@ class ImagePut { : "SDnRcw5EOQF1A0SJCUiDwQTr7cM=") ; Select top-left pixel as default. - key == "sentinel" && key := NumGet(this.ptr, "uint") + (key == "sentinel") && key := NumGet(this.ptr, "uint") ; Replaces one ARGB color with another. DllCall(code, "ptr", this.ptr, "uint", this.ptr + this.size, "uint", key, "uint", value) @@ -2234,7 +2234,7 @@ class ImagePut { : "SDnRcxaLAUQxwKn///8AdQREiEkDSIPBBOvlww==") ; Select top-left pixel as default. - color == "sentinel" && color := NumGet(this.ptr, "uint") + (color == "sentinel") && color := NumGet(this.ptr, "uint") ; Sets the alpha value of a specified RGB color. DllCall(code, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "uchar", alpha) @@ -2301,6 +2301,42 @@ class ImagePut { return [mod(offset, this.width), offset // this.width] } + PixelSearchAll(color) { + ; C source code - https://godbolt.org/z/zPY1qMvYe + static PixelSearch3 := 0 + (PixelSearch3) || PixelSearch3 := this.Base64Put((A_PtrSize == 4) + ? "VYnli1UMi00Qi0UIOdBzCTkIdAeDwATr84nQXcM=" + : "McBEi1QkKE05yHMYRTkQdQ050HMHQYnDTokE2f/ASYPABOvjww==") + + ; Lift color to 32-bits if first 8 bits are zero. + (color >> 24) || color |= 0xFF000000 + + ; PixelSearchAll, single color, no variation + capacity := 256 + VarSetCapacity(result, A_PtrSize * capacity) + count := DllCall(PixelSearch3, "ptr", &result, "uint", capacity, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "uint") + + ; If the default 256 results is exceeded, run the function again. + if (count > capacity) { + VarSetCapacity(result, A_PtrSize * count) + count := DllCall(PixelSearch3, "ptr", &result, "uint", count, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "uint") + } + + ; Check if any matches are found. + if (count = 0) + return False + + ; Create an array of [x, y] coordinates. + xys := [] + loop % count { + byte := NumGet(result, A_PtrSize*(A_Index-1), "ptr") + offset := (byte - this.ptr) // 4 + xy := [mod(offset, this.width), offset // this.width] + xys.push(xy) + } + return xys + } + ImageSearch(image) { ; C source code - https://godbolt.org/z/qPodGdP1d static code := 0 diff --git a/ImagePut.ahk b/ImagePut.ahk index ba019b45..9448a881 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2209,7 +2209,7 @@ class ImagePut { : "SDnRcw5EOQF1A0SJCUiDwQTr7cM=") ; Select top-left pixel as default. - key == "sentinel" && key := NumGet(this.ptr, "uint") + (key == "sentinel") && key := NumGet(this.ptr, "uint") ; Replaces one ARGB color with another. DllCall(code, "ptr", this.ptr, "uint", this.ptr + this.size, "uint", key, "uint", value) @@ -2234,7 +2234,7 @@ class ImagePut { : "SDnRcxaLAUQxwKn///8AdQREiEkDSIPBBOvlww==") ; Select top-left pixel as default. - color == "sentinel" && color := NumGet(this.ptr, "uint") + (color == "sentinel") && color := NumGet(this.ptr, "uint") ; Sets the alpha value of a specified RGB color. DllCall(code, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "uchar", alpha) From 9b5abd1fcd043b16fe68498759e36c3db595aef8 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 19 Dec 2022 20:12:52 -0500 Subject: [PATCH 368/492] sync PixelSearchAll --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 61a2bf39..c136d22a 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2305,7 +2305,7 @@ class ImagePut { ; C source code - https://godbolt.org/z/zPY1qMvYe static PixelSearch3 := 0 (PixelSearch3) || PixelSearch3 := this.Base64Put((A_PtrSize == 4) - ? "VYnli1UMi00Qi0UIOdBzCTkIdAeDwATr84nQXcM=" + ? "VTHAieVTi1UQi00UOcpzGItdGDkadQw7RQxzBotdCIkUg0CDwgTr5Ftdww==" : "McBEi1QkKE05yHMYRTkQdQ050HMHQYnDTokE2f/ASYPABOvjww==") ; Lift color to 32-bits if first 8 bits are zero. diff --git a/ImagePut.ahk b/ImagePut.ahk index 9448a881..3cb68822 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2305,7 +2305,7 @@ class ImagePut { ; C source code - https://godbolt.org/z/zPY1qMvYe static PixelSearch3 := 0 (PixelSearch3) || PixelSearch3 := this.Base64Put((A_PtrSize == 4) - ? "VYnli1UMi00Qi0UIOdBzCTkIdAeDwATr84nQXcM=" + ? "VTHAieVTi1UQi00UOcpzGItdGDkadQw7RQxzBotdCIkUg0CDwgTr5Ftdww==" : "McBEi1QkKE05yHMYRTkQdQ050HMHQYnDTokE2f/ASYPABOvjww==") ; Lift color to 32-bits if first 8 bits are zero. From a96e8dbd6e68b735d48c29e8e82c84e3b6ec7c92 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 19 Dec 2022 23:01:54 -0500 Subject: [PATCH 369/492] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d7611c38..8a384196 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ #### A core library for images in AutoHotkey -* Screen capture with fast [PixelSearch](https://github.com/iseahound/ImagePut/wiki/PixelSearch-and-ImageSearch#pixelsearch) and ImageSearch +* Screen capture with fast [PixelSearch](https://github.com/iseahound/ImagePut/wiki/PixelSearch-and-ImageSearch#pixelsearch) and [ImageSearch](https://github.com/iseahound/ImagePut/wiki/PixelSearch-and-ImageSearch#imagesearch) * Decipher over [20+ image types](https://github.com/iseahound/ImagePut/wiki/Quick-Start#accepts) * Convert from one image format to another * View and debug your image functions with `ImagePutWindow(image)` From ee17a8e1a5eaf8182665c8161eb8d9107cbe21e1 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 22 Dec 2022 23:26:24 -0500 Subject: [PATCH 370/492] Allow "image" in ImageSearchAll to be magical --- ImagePut (for v1).ahk | 50 +++++++++++++++++++++++++++++++++++++++++-- ImagePut.ahk | 14 ++++++++---- 2 files changed, 58 insertions(+), 6 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index c136d22a..511b84aa 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2348,8 +2348,8 @@ class ImagePut { . "0kwp2EjB+AJB9/I513w8TInIRTHkMdI52nQ+RYnlTI00KE6NLKlMOfBzGYB4AwB0CUWLfQBEOTh1EUiDwARJg8UE6+L/wkUB1OvM" . "SIPBBOuYRQ+vwkuNDINIichbXl9dQVxBXUFeQV/D") - ; Check for a .pBitmap property - if !(IsObject(image) && ObjHasKey(image, "pBitmap")) + ; Convert image to a buffer object. + if !(IsObject(image) && ObjHasKey(image, "ptr") && ObjHasKey(image, "size")) image := ImagePutBuffer(image) ; Search for the address of the first matching image. @@ -2364,6 +2364,52 @@ class ImagePut { offset := (byte - this.ptr) // 4 return [mod(offset, this.width), offset // this.width] } + + ImageSearchAll(image) { + ; C source code - https://godbolt.org/z/qPodGdP1d + static code := 0 + (code) || code := this.Base64Put((A_PtrSize == 4) + ? "VYnlV1ZTg+wUi0UMi1UYi00IjTyFAAAAAItFECtFHA+vxwNFCIlF6ItFDCnQiUXkjQSVAAAAAIlF7ItF6DnBc2eLRRSLADkBdAmL" + . "RRSAeAMAdVCJyCtFCDHSwfgC93UMOVXkfD4x0otFFInLiVXwi3XwO3UcdDyLVeyJ3gHCiVXgi1XgOdBzFIB4AwB0BosWORB1D4PA" + . "BIPGBOvl/0XwAfvrzIPBBOuSi0UQD6/HA0UIicGDxBSJyFteX13D" + : "QVdBVkFVQVRVV1ZTSIPsGEUx20SLpCSYAAAAi4QkgAAAAESLlCSQAAAASIu8JIgAAABEKeBBD6/BSInLidZMicFNjSyARInIRCnQ" + . "iUQkDEqNBJUAAAAASIkEJEw56XN0iwc5AXQGgH8DAHViSInIMdJMKcBIwfgCQffxOVQkDHxNSIn4Me0x0kQ54nQyTIs8JEGJ7k6N" + . "NLFJAcdMOfhzGIB4AwB0CEWLFkQ5EHUgSIPABEmDxgTr4//CRAHN68lBOfNzB0SJ2EiJDMNB/8NIg8EE64dEidhIg8QYW15fXUFc" + . "QV1BXkFfww==") + + ; Convert image to a buffer object. + if !(IsObject(image) && ObjHasKey(image, "ptr") && ObjHasKey(image, "size")) + image := ImagePutBuffer(image) + + ; Search for the address of the first matching image. + capacity := 256 + VarSetCapacity(result, A_PtrSize * capacity) + count := DllCall(code, "ptr", &result, "uint", capacity + , "ptr", this.ptr, "uint", this.width, "uint", this.height + , "ptr", image.ptr, "uint", image.width, "uint", image.height, "uint") + + ; If more than 256 results, run the function with the true capacity. + if (count > capacity) { + VarSetCapacity(result, A_PtrSize * count) + count := DllCall(code, "ptr", &result, "uint", capacity + , "ptr", this.ptr, "uint", this.width, "uint", this.height + , "ptr", image.ptr, "uint", image.width, "uint", image.height, "uint") + } + + ; Check if any matches are found. + if (count = 0) + return False + + ; Create an array of [x, y] coordinates. + xys := [] + loop % count { + byte := NumGet(result, A_PtrSize*(A_Index-1), "ptr") + offset := (byte - this.ptr) // 4 + xy := [mod(offset, this.width), offset // this.width] + xys.push(xy) + } + return xys + } } put_screenshot(pBitmap, screenshot := "", alpha := "") { diff --git a/ImagePut.ahk b/ImagePut.ahk index 3cb68822..f8d9f5cf 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2348,8 +2348,8 @@ class ImagePut { . "0kwp2EjB+AJB9/I513w8TInIRTHkMdI52nQ+RYnlTI00KE6NLKlMOfBzGYB4AwB0CUWLfQBEOTh1EUiDwARJg8UE6+L/wkUB1OvM" . "SIPBBOuYRQ+vwkuNDINIichbXl9dQVxBXUFeQV/D") - ; Check for a .pBitmap property - if !(IsObject(image) && ObjHasOwnProp(image, "pBitmap")) + ; Convert image to a buffer object. + if !(IsObject(image) && ObjHasOwnProp(image, "ptr") && ObjHasOwnProp(image, "size")) image := ImagePutBuffer(image) ; Search for the address of the first matching image. @@ -2372,8 +2372,14 @@ class ImagePut { ? "VYnlV1ZTg+wUi0UMi1UYi00IjTyFAAAAAItFECtFHA+vxwNFCIlF6ItFDCnQiUXkjQSVAAAAAIlF7ItF6DnBc2eLRRSLADkBdAmL" . "RRSAeAMAdVCJyCtFCDHSwfgC93UMOVXkfD4x0otFFInLiVXwi3XwO3UcdDyLVeyJ3gHCiVXgi1XgOdBzFIB4AwB0BosWORB1D4PA" . "BIPGBOvl/0XwAfvrzIPBBOuSi0UQD6/HA0UIicGDxBSJyFteX13D" - : "QVdBVkFVQVRVV1ZTSIPsGEUx20SLpCSYAAAAi4QkgAAAAESLlCSQAAAASIu8JIgAAABEKeBBD6/BSInLidZMicFNjSyARInIRCnQiUQkDEqNBJUAAAAASIkEJEw56XN0iwc5AXQGgH8DAHViSInIMdJMKcBIwfgCQffxOVQkDHxNSIn4Me0x0kQ54nQyTIs8JEGJ7k6NNLFJAcdMOfhzGIB4AwB0CEWLFkQ5EHUgSIPABEmDxgTr4//CRAHN68lBOfNzB0SJ2EiJDMNB/8NIg8EE64dEidhIg8QYW15fXUFcQV1BXkFfww==" -) + : "QVdBVkFVQVRVV1ZTSIPsGEUx20SLpCSYAAAAi4QkgAAAAESLlCSQAAAASIu8JIgAAABEKeBBD6/BSInLidZMicFNjSyARInIRCnQ" + . "iUQkDEqNBJUAAAAASIkEJEw56XN0iwc5AXQGgH8DAHViSInIMdJMKcBIwfgCQffxOVQkDHxNSIn4Me0x0kQ54nQyTIs8JEGJ7k6N" + . "NLFJAcdMOfhzGIB4AwB0CEWLFkQ5EHUgSIPABEmDxgTr4//CRAHN68lBOfNzB0SJ2EiJDMNB/8NIg8EE64dEidhIg8QYW15fXUFc" + . "QV1BXkFfww==") + + ; Convert image to a buffer object. + if !(IsObject(image) && ObjHasOwnProp(image, "ptr") && ObjHasOwnProp(image, "size")) + image := ImagePutBuffer(image) ; Search for the address of the first matching image. capacity := 256 From 5e10901fc6d0bde2d3b5611b97f925bfdb86c983 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 21 Jan 2023 13:12:27 -0500 Subject: [PATCH 371/492] Fix crop() on v1 by removing "new" call --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 511b84aa..b690d78c 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2093,7 +2093,7 @@ class ImagePut { Crop(x, y, w, h) { DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", this.pBitmap, "int*", format:=0) DllCall("gdiplus\GdipCloneBitmapAreaI", "int", x, "int", y, "int", w, "int", h, "int", format, "ptr", this.pBitmap, "ptr*", pBitmap:=0) - return new ImagePut.put_buffer(pBitmap) + return ImagePut.put_buffer(pBitmap) } Show(window_border := False, title := "", pos := "", style := "", styleEx := "", parent := "") { diff --git a/ImagePut.ahk b/ImagePut.ahk index f8d9f5cf..28de9f10 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2410,6 +2410,12 @@ class ImagePut { } return xys } + + ; Statistics + + Frequency(c*) { + return 1 + } } static put_screenshot(pBitmap, screenshot := "", alpha := "") { From 7ffeefa913ff0d18391b821b0669a99b3a6ae617 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 30 Jan 2023 00:08:21 -0500 Subject: [PATCH 372/492] Add simple count* colors function --- ImagePut (for v1).ahk | 20 ++++++++++++++++++++ ImagePut.ahk | 26 ++++++++++++++++++++------ 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index b690d78c..cb15b902 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2090,6 +2090,26 @@ class ImagePut { + Frequency() { + if this.HasKey(map) + return + this.map := {} + loop % this.width * this.height + if c := NumGet(this.ptr + 4*(A_Index-1), "uint") + this.map[c] := this.map.haskey(c) ? this.map[c] + 1 : 1 + } + + Count(c*) { + this.Frequency() + acc := 0 + for each, color in c { + ; Lift color to 32-bits if first 8 bits are zero. + (color >> 24) || color |= 0xFF000000 + acc += this.map[color] + } + return acc + } + Crop(x, y, w, h) { DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", this.pBitmap, "int*", format:=0) DllCall("gdiplus\GdipCloneBitmapAreaI", "int", x, "int", y, "int", w, "int", h, "int", format, "ptr", this.pBitmap, "ptr*", pBitmap:=0) diff --git a/ImagePut.ahk b/ImagePut.ahk index 28de9f10..8bedd675 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2090,6 +2090,26 @@ class ImagePut { } } + Frequency() { + if this.HasProp(map) + return + this.map := Map() + loop this.width * this.height + if c := NumGet(this.ptr + 4*(A_Index-1), "uint") + this.map[c] := this.map.has(c) ? this.map[c] + 1 : 1 + } + + Count(c*) { + this.Frequency() + acc := 0 + for each, color in c { + ; Lift color to 32-bits if first 8 bits are zero. + (color >> 24) || color |= 0xFF000000 + acc += this.map.get(color, 0) + } + return acc + } + Crop(x, y, w, h) { DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", this.pBitmap, "int*", &format:=0) DllCall("gdiplus\GdipCloneBitmapAreaI", "int", x, "int", y, "int", w, "int", h, "int", format, "ptr", this.pBitmap, "ptr*", &pBitmap:=0) @@ -2410,12 +2430,6 @@ class ImagePut { } return xys } - - ; Statistics - - Frequency(c*) { - return 1 - } } static put_screenshot(pBitmap, screenshot := "", alpha := "") { From a7494a1e70e5e6d519081bdfe8b01c8143c1b28c Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 30 Jan 2023 07:49:50 -0500 Subject: [PATCH 373/492] Add Clone() using memcpy --- ImagePut (for v1).ahk | 7 +++++++ ImagePut.ahk | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index cb15b902..3d50ba3f 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2110,6 +2110,13 @@ class ImagePut { return acc } + Clone() { + ptr := DllCall("GlobalAlloc", "uint", 0, "uptr", this.size, "ptr") + DllCall("RtlMoveMemory", "ptr", ptr, "ptr", this.ptr, "uptr", this.size) + free := Func("DllCall").bind("GlobalFree", "ptr", ptr) + return new ImagePut.BitmapBuffer(ptr, this.size, this.width, this.height, free) + } + Crop(x, y, w, h) { DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", this.pBitmap, "int*", format:=0) DllCall("gdiplus\GdipCloneBitmapAreaI", "int", x, "int", y, "int", w, "int", h, "int", format, "ptr", this.pBitmap, "ptr*", pBitmap:=0) diff --git a/ImagePut.ahk b/ImagePut.ahk index 8bedd675..6dfd31f0 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2110,6 +2110,13 @@ class ImagePut { return acc } + Clone() { + ptr := DllCall("GlobalAlloc", "uint", 0, "uptr", this.size, "ptr") + DllCall("RtlMoveMemory", "ptr", ptr, "ptr", this.ptr, "uptr", this.size) + free := DllCall.bind("GlobalFree", "ptr", ptr) + return ImagePut.BitmapBuffer(ptr, this.size, this.width, this.height, free) + } + Crop(x, y, w, h) { DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", this.pBitmap, "int*", &format:=0) DllCall("gdiplus\GdipCloneBitmapAreaI", "int", x, "int", y, "int", w, "int", h, "int", format, "ptr", this.pBitmap, "ptr*", &pBitmap:=0) From 00094feca5de357aca78c0246577d941d1435ed1 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 4 Feb 2023 11:57:17 -0500 Subject: [PATCH 374/492] (v2) Avoid SingleInstance Checks --- ImagePut (for v1).ahk | 2 ++ ImagePut.ahk | 2 ++ 2 files changed, 4 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 3d50ba3f..309878c8 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -3924,6 +3924,8 @@ ImagePut_dropfiles() { filepath := "" } } + + } ; Drag and drop files directly onto this script file. diff --git a/ImagePut.ahk b/ImagePut.ahk index 6dfd31f0..c1b3490e 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -3924,6 +3924,8 @@ ImagePut_dropfiles() { filepath := "" } } + ; Avoid SingleInstance checks. Only seems to be necessary on v2. + WinSetTitle WinGetTitle(A_ScriptHwnd) . A_ScriptHwnd, A_ScriptHwnd } ; Drag and drop files directly onto this script file. From b0aa7e2168a3de62698eaa7011b4a672a66b9ea1 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 4 Feb 2023 12:04:05 -0500 Subject: [PATCH 375/492] Guard against static pToken is unset --- ImagePut (for v1).ahk | 3 +++ ImagePut.ahk | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 309878c8..d828b062 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -3634,6 +3634,9 @@ class ImagePut { static pToken := 0 ; Takes advantage of the fact that objects contain identical methods. static instances := 0 ; And therefore static variables can share data across instances. + + + ; Startup gdiplus when counter rises from 0 -> 1. if (instances = 0 && vary = 1) { diff --git a/ImagePut.ahk b/ImagePut.ahk index c1b3490e..6022b997 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -3634,6 +3634,10 @@ class ImagePut { static pToken := 0 ; Takes advantage of the fact that objects contain identical methods. static instances := 0 ; And therefore static variables can share data across instances. + ; Guard against __Delete() errors. + if not IsSet(pToken) || not IsSet(instances) + return + ; Startup gdiplus when counter rises from 0 -> 1. if (instances = 0 && vary = 1) { From 0ec28afd0b5a5048042e7f75a63f593b38e1c073 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 4 Feb 2023 12:32:55 -0500 Subject: [PATCH 376/492] Remove IsObject checks due to v2-beta.13 --- ImagePut (for v1).ahk | 8 ++++---- ImagePut.ahk | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index d828b062..31869ef7 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1969,8 +1969,8 @@ class ImagePut { __Delete() { DllCall("gdiplus\GdipDisposeImage", "ptr", this.pBitmap) - IsObject(ImagePut) && this.free && this.free.call() - IsObject(ImagePut) && ImagePut.gdiplusShutdown() + this.free.call() + ImagePut.gdiplusShutdown() } __Get(x, y) { @@ -2803,7 +2803,7 @@ class ImagePut { DllCall("GlobalFree", "ptr", Item) ; Exit GDI+ conditionally due to the ImagePut class being destroyed first. - IsObject(ImagePut) && ImagePut.gdiplusShutdown() + ImagePut.gdiplusShutdown() } Hotkey % "^+F12", % void, Off ; Cannot disable, does nothing } @@ -3635,7 +3635,7 @@ class ImagePut { static instances := 0 ; And therefore static variables can share data across instances. - + ; Startup gdiplus when counter rises from 0 -> 1. if (instances = 0 && vary = 1) { diff --git a/ImagePut.ahk b/ImagePut.ahk index 6022b997..5b1e9b4a 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -5,7 +5,7 @@ ; Date: 2022-11-06 ; Version: 1.9 -#Requires AutoHotkey v2.0-beta.3+ +#Requires AutoHotkey v2.0-beta.13+ ; Puts the image into a file format and returns a base64 encoded string. @@ -1969,8 +1969,8 @@ class ImagePut { __Delete() { DllCall("gdiplus\GdipDisposeImage", "ptr", this.pBitmap) - IsObject(ImagePut) && HasMethod(this.free) && this.free.call() - IsObject(ImagePut) && ImagePut.gdiplusShutdown() + this.free.call() + ImagePut.gdiplusShutdown() } __Item[x, y] { @@ -2803,7 +2803,7 @@ class ImagePut { DllCall("GlobalFree", "ptr", Item) ; Exit GDI+ conditionally due to the ImagePut class being destroyed first. - IsObject(ImagePut) && ImagePut.gdiplusShutdown() + ImagePut.gdiplusShutdown() } Persistent(--active_windows) } From 7f9b5dc6ce3353111424a5e66a6b96cf0fb59c9e Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 4 Feb 2023 12:37:20 -0500 Subject: [PATCH 377/492] Fix 1st parameter of ImagePutExplorer --- ImagePut (for v1).ahk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 31869ef7..4af9b692 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -584,7 +584,7 @@ class ImagePut { ; BitmapToCoimage("explorer", pBitmap, default) if (cotype = "explorer") - return this.put_explorer(pBitmap, default) + return this.put_explorer(pBitmap, p1) ; BitmapToCoimage("safeArray", pBitmap, extension, quality) if (cotype = "safeArray") From 84042a10e235acbdfb56421520677115f292c017 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 4 Feb 2023 12:38:24 -0500 Subject: [PATCH 378/492] trim backspace --- ImagePut (for v1).ahk | 8 ++++---- ImagePut.ahk | 18 +++++++++--------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 4af9b692..3f8d2fb8 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -661,7 +661,7 @@ class ImagePut { ; StreamToCoimage("safeArray", pStream) if (cotype = "safeArray") return this.set_safeArray(pStream) - + ; StreamToCoimage("formData", pStream, boundary) if (cotype = "formData") return this.set_formData(pStream, p1) @@ -2109,7 +2109,7 @@ class ImagePut { } return acc } - + Clone() { ptr := DllCall("GlobalAlloc", "uint", 0, "uptr", this.size, "ptr") DllCall("RtlMoveMemory", "ptr", ptr, "ptr", this.ptr, "uptr", this.size) @@ -2299,7 +2299,7 @@ class ImagePut { else if (variation == 0) { ; Get the address of the first matching pixel. byte := DllCall(PixelSearch, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "ptr") - } + } ; PixelSearch, single color, and variation else { @@ -3048,7 +3048,7 @@ class ImagePut { MouseGetPos,,, hwnd WinGetClass class, ahk_id %hwnd% if (class ~= "(?i)Progman|WorkerW") - directory := A_Desktop + directory := A_Desktop ; Get path of active window. else if (hwnd := WinExist("ahk_class ExploreWClass")) || (hwnd := WinExist("ahk_class CabinetWClass")) { diff --git a/ImagePut.ahk b/ImagePut.ahk index 5b1e9b4a..09e8374e 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -882,7 +882,7 @@ class ImagePut { throw ValueError(message, -1, statement) } - ; Load DirectX + ; Load DirectX assert IDXGIFactory := CreateDXGIFactory(), "Create IDXGIFactory failed." CreateDXGIFactory() { @@ -1984,17 +1984,17 @@ class ImagePut { start := 0 end := this.size - + switch n { case 1: enum1(&c) { - + if start == end return False ; yield statements c := Format("0x{:X}", NumGet(this, start, "uint")) - + ; do block start += 4 @@ -2012,7 +2012,7 @@ class ImagePut { ; yield statements i := start // 4 c := Format("0x{:X}", NumGet(this, start, "uint")) - + ; do block start += 4 @@ -2020,7 +2020,7 @@ class ImagePut { return start <= end } return enum2 - + case 3: enum3(&x, &y, &c) { @@ -2299,7 +2299,7 @@ class ImagePut { else if (variation == 0) { ; Get the address of the first matching pixel. byte := DllCall(PixelSearch, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "ptr") - } + } ; PixelSearch, single color, and variation else { @@ -3046,7 +3046,7 @@ class ImagePut { ; Check if the mouse is pointing to the desktop. MouseGetPos ,, &hwnd - + if WinGetClass("ahk_id" hwnd) ~= "(?i)Progman|WorkerW" directory := A_Desktop @@ -3071,7 +3071,7 @@ class ImagePut { ; Check if the mouse is pointing to the desktop. MouseGetPos ,, &hwnd - + if WinGetClass("ahk_id" hwnd) ~= "(?i)Progman|WorkerW" directory := A_Desktop From 5b6ebdcefb7d19709653e86dc73a76a09a48ab93 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 4 Feb 2023 12:40:49 -0500 Subject: [PATCH 379/492] lowercase hresult --- ImagePut.ahk | 104 +++++++++++++++++++++++++-------------------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index 09e8374e..4144161c 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -862,7 +862,7 @@ class ImagePut { ; Allow the stream to be freed while leaving the hData intact. ; Please read: https://devblogs.microsoft.com/oldnewthing/20210930-00/?p=105745 - DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", False, "ptr*", &pStream:=0, "HRESULT") + DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", False, "ptr*", &pStream:=0, "hresult") DllCall("CloseClipboard") return pStream } @@ -890,8 +890,8 @@ class ImagePut { DllCall("LoadLibrary", "str", "DXGI") if !DllCall("GetModuleHandle", "str", "D3D11") DllCall("LoadLibrary", "str", "D3D11") - DllCall("ole32\CLSIDFromString", "wstr", "{7b7166ec-21c7-44ae-b21a-c9ae321ae369}", "ptr", riid := Buffer(16, 0), "HRESULT") - DllCall("DXGI\CreateDXGIFactory1", "ptr", riid, "ptr*", &ppFactory:=0, "HRESULT") + DllCall("ole32\CLSIDFromString", "wstr", "{7b7166ec-21c7-44ae-b21a-c9ae321ae369}", "ptr", riid := Buffer(16, 0), "hresult") + DllCall("DXGI\CreateDXGIFactory1", "ptr", riid, "ptr*", &ppFactory:=0, "hresult") return ppFactory } @@ -930,7 +930,7 @@ class ImagePut { , "ptr*", &d3d_device:=0 ; ppDevice , "ptr*", 0 ; pFeatureLevel , "ptr*", &d3d_context:=0 ; ppImmediateContext - ,"HRESULT") + ,"hresult") ; Retrieve the desktop duplication API IDXGIOutput1 := ComObjQuery(IDXGIOutput, "{00cddea8-939b-4b83-a340-a685226666cc}") @@ -1299,20 +1299,20 @@ class ImagePut { pStream := this.is_url(image) ? this.get_url(image) : this.get_file(image) ; Compare the signature of the file with the PDF magic string "%PDF". - DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", signature := Buffer(4), "uint", 4, "HRESULT") + DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", signature := Buffer(4), "uint", 4, "hresult") StrPut("%PDF", magic := Buffer(4), "CP0") if 4 > DllCall("ntdll\RtlCompareMemory", "ptr", signature, "ptr", magic, "uptr", 4, "uptr") throw Error("Invalid PDF.") ; Create a RandomAccessStream with BSOS_PREFERDESTINATIONSTREAM. - DllCall("ole32\CLSIDFromString", "wstr", "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}", "ptr", CLSID := Buffer(16), "HRESULT") - DllCall("ShCore\CreateRandomAccessStreamOverStream", "ptr", pStream, "uint", 1, "ptr", CLSID, "ptr*", &pRandomAccessStream:=0, "HRESULT") + DllCall("ole32\CLSIDFromString", "wstr", "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}", "ptr", CLSID := Buffer(16), "hresult") + DllCall("ShCore\CreateRandomAccessStreamOverStream", "ptr", pStream, "uint", 1, "ptr", CLSID, "ptr*", &pRandomAccessStream:=0, "hresult") ; Create the "Windows.Data.Pdf.PdfDocument" class using IPdfDocumentStatics. - DllCall("combase\WindowsCreateString", "wstr", "Windows.Data.Pdf.PdfDocument", "uint", 28, "ptr*", &hString:=0, "HRESULT") - DllCall("ole32\CLSIDFromString", "wstr", "{433A0B5F-C007-4788-90F2-08143D922599}", "ptr", CLSID := Buffer(16), "HRESULT") - DllCall("combase\RoGetActivationFactory", "ptr", hString, "ptr", CLSID, "ptr*", &PdfDocumentStatics:=0, "HRESULT") - DllCall("combase\WindowsDeleteString", "ptr", hString, "HRESULT") + DllCall("combase\WindowsCreateString", "wstr", "Windows.Data.Pdf.PdfDocument", "uint", 28, "ptr*", &hString:=0, "hresult") + DllCall("ole32\CLSIDFromString", "wstr", "{433A0B5F-C007-4788-90F2-08143D922599}", "ptr", CLSID := Buffer(16), "hresult") + DllCall("combase\RoGetActivationFactory", "ptr", hString, "ptr", CLSID, "ptr*", &PdfDocumentStatics:=0, "hresult") + DllCall("combase\WindowsDeleteString", "ptr", hString, "hresult") ; Create the PDF document. ComCall(IPdfDocumentStatics_LoadFromStreamAsync := 8, PdfDocumentStatics, "ptr", pRandomAccessStream, "ptr*", &PdfDocument:=0) @@ -1332,7 +1332,7 @@ class ImagePut { ; Render the page to an output stream. DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "uint", True, "ptr*", &pStreamOut:=0) - DllCall("ole32\CLSIDFromString", "wstr", "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}", "ptr", CLSID := Buffer(16), "HRESULT") + DllCall("ole32\CLSIDFromString", "wstr", "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}", "ptr", CLSID := Buffer(16), "hresult") DllCall("ShCore\CreateRandomAccessStreamOverStream", "ptr", pStreamOut, "uint", BSOS_DEFAULT := 0, "ptr", CLSID, "ptr*", &pRandomAccessStreamOut:=0) ComCall(IPdfPage_RenderToStreamAsync := 6, PdfPage, "ptr", pRandomAccessStreamOut, "ptr*", &AsyncInfo:=0) this.WaitForAsync(&AsyncInfo) @@ -1411,7 +1411,7 @@ class ImagePut { file.RawRead(pData, file.length) DllCall("GlobalUnlock", "ptr", hData) file.Close() - DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", True, "ptr*", &pStream:=0, "HRESULT") + DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", True, "ptr*", &pStream:=0, "hresult") return pStream } @@ -1437,7 +1437,7 @@ class ImagePut { DllCall("crypt32\CryptStringToBinary", "str", image, "uint", 0, "uint", flags, "ptr", pData, "uint*", size, "ptr", 0, "ptr", 0) DllCall("GlobalUnlock", "ptr", hData) - DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", True, "ptr*", &pStream:=0, "HRESULT") + DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", True, "ptr*", &pStream:=0, "hresult") return pStream } @@ -1463,7 +1463,7 @@ class ImagePut { DllCall("crypt32\CryptStringToBinary", "str", image, "uint", 0, "uint", flags, "ptr", pData, "uint*", size, "ptr", 0, "ptr", 0) DllCall("GlobalUnlock", "ptr", hData) - DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", True, "ptr*", &pStream:=0, "HRESULT") + DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", True, "ptr*", &pStream:=0, "hresult") return pStream } @@ -1736,8 +1736,8 @@ class ImagePut { static get_RandomAccessStream(image) { ; Note that the returned stream shares a reference count with the original RandomAccessStream's internal stream. - DllCall("ole32\CLSIDFromString", "wstr", "{0000000C-0000-0000-C000-000000000046}", "ptr", CLSID := Buffer(16), "HRESULT") - DllCall("ShCore\CreateStreamOverRandomAccessStream", "ptr", image, "ptr", CLSID, "ptr*", &pStream:=0, "HRESULT") + DllCall("ole32\CLSIDFromString", "wstr", "{0000000C-0000-0000-C000-000000000046}", "ptr", CLSID := Buffer(16), "hresult") + DllCall("ShCore\CreateStreamOverRandomAccessStream", "ptr", image, "ptr", CLSID, "ptr*", &pStream:=0, "hresult") return pStream } @@ -1838,10 +1838,10 @@ class ImagePut { ; Create a Stream whose underlying HGlobal must be referenced or lost forever. ; Rescue the HGlobal after GDI+ has written the PNG to stream and release the stream. ; Please read: https://devblogs.microsoft.com/oldnewthing/20210929-00/?p=105742 - DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "int", False, "ptr*", &pStream:=0, "HRESULT") + DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "int", False, "ptr*", &pStream:=0, "hresult") this.select_codec(pBitmap, "png", "", &pCodec, &ep, &ci, &v) DllCall("gdiplus\GdipSaveImageToStream", "ptr", pBitmap, "ptr", pStream, "ptr", pCodec, "ptr", IsSet(ep) ? ep : 0) - DllCall("ole32\GetHGlobalFromStream", "ptr", pStream, "uint*", &hData:=0, "HRESULT") + DllCall("ole32\GetHGlobalFromStream", "ptr", pStream, "uint*", &hData:=0, "hresult") ObjRelease(pStream) ; Set the rescued HGlobal to the clipboard as a shared object. @@ -3120,11 +3120,11 @@ class ImagePut { , "int", True ; fCreate is ignored when STGM_CREATE is set. , "ptr", 0 ; pstmTemplate (reserved) , "ptr*", &pFileStream:=0 - ,"HRESULT") - DllCall("shlwapi\IStream_Size", "ptr", pStream, "uint64*", &size:=0, "HRESULT") - DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") - DllCall("shlwapi\IStream_Copy", "ptr", pStream, "ptr", pFileStream, "uint", size, "HRESULT") - DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") + ,"hresult") + DllCall("shlwapi\IStream_Size", "ptr", pStream, "uint64*", &size:=0, "hresult") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "hresult") + DllCall("shlwapi\IStream_Copy", "ptr", pStream, "ptr", pFileStream, "uint", size, "hresult") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "hresult") ObjRelease(pFileStream) return filepath @@ -3140,7 +3140,7 @@ class ImagePut { pStream := this.put_stream(pBitmap, extension, quality) ; Get a pointer to binary data. - DllCall("ole32\GetHGlobalFromStream", "ptr", pStream, "ptr*", &hbin:=0, "HRESULT") + DllCall("ole32\GetHGlobalFromStream", "ptr", pStream, "ptr*", &hbin:=0, "hresult") bin := DllCall("GlobalLock", "ptr", hbin, "ptr") size := DllCall("GlobalSize", "ptr", bin, "uptr") @@ -3175,10 +3175,10 @@ class ImagePut { static set_hex(pStream) { ; For compatibility with SHCreateMemStream do not use GetHGlobalFromStream. - DllCall("shlwapi\IStream_Size", "ptr", pStream, "uint64*", &size:=0, "HRESULT") - DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") - DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", bin := Buffer(size), "uint", size, "HRESULT") - DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") + DllCall("shlwapi\IStream_Size", "ptr", pStream, "uint64*", &size:=0, "hresult") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "hresult") + DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", bin := Buffer(size), "uint", size, "hresult") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "hresult") ; Calculate the length of the hexadecimal string. length := 2 * size ; No zero terminator needed. @@ -3215,7 +3215,7 @@ class ImagePut { pStream := this.put_stream(pBitmap, extension, quality) ; Get a pointer to binary data. - DllCall("ole32\GetHGlobalFromStream", "ptr", pStream, "ptr*", &hbin:=0, "HRESULT") + DllCall("ole32\GetHGlobalFromStream", "ptr", pStream, "ptr*", &hbin:=0, "hresult") bin := DllCall("GlobalLock", "ptr", hbin, "ptr") size := DllCall("GlobalSize", "ptr", bin, "uptr") @@ -3237,10 +3237,10 @@ class ImagePut { static set_base64(pStream) { ; For compatibility with SHCreateMemStream do not use GetHGlobalFromStream. - DllCall("shlwapi\IStream_Size", "ptr", pStream, "uint64*", &size:=0, "HRESULT") - DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") - DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", bin := Buffer(size), "uint", size, "HRESULT") - DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") + DllCall("shlwapi\IStream_Size", "ptr", pStream, "uint64*", &size:=0, "hresult") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "hresult") + DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", bin := Buffer(size), "uint", size, "hresult") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "hresult") ; Calculate the length of the base64 string. flags := 0x40000001 ; CRYPT_STRING_NOCRLF | CRYPT_STRING_BASE64 @@ -3263,9 +3263,9 @@ class ImagePut { } static set_uri(pStream) { - DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") - DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", signature := Buffer(256), "uint", 256, "HRESULT") - DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "hresult") + DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", signature := Buffer(256), "uint", 256, "hresult") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "hresult") ; This function sniffs the first 256 bytes and matches a known file signature. ; 256 bytes is recommended, but images only need 12 bytes. @@ -3279,7 +3279,7 @@ class ImagePut { , "uint", 0x20 ; dwMimeFlags , "ptr*", &MimeOut:=0 ; ppwzMimeOut , "uint", 0 ; dwReserved - ,"HRESULT") + ,"hresult") MimeType := StrGet(MimeOut, "UTF-16") DllCall("ole32\CoTaskMemFree", "ptr", MimeOut) @@ -3387,7 +3387,7 @@ class ImagePut { this.select_codec(pBitmap, extension, quality, &pCodec, &ep, &ci, &v) ; Create a Stream. - DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "int", True, "ptr*", &pStream:=0, "HRESULT") + DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "int", True, "ptr*", &pStream:=0, "hresult") DllCall("gdiplus\GdipSaveImageToStream", "ptr", pBitmap, "ptr", pStream, "ptr", pCodec, "ptr", IsSet(ep) ? ep : 0) return pStream @@ -3402,13 +3402,13 @@ class ImagePut { static set_RandomAccessStream(pStream) { ; Thanks teadrinker - https://www.autohotkey.com/boards/viewtopic.php?f=6&t=72674 - DllCall("ole32\CLSIDFromString", "wstr", "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}", "ptr", CLSID := Buffer(16), "HRESULT") + DllCall("ole32\CLSIDFromString", "wstr", "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}", "ptr", CLSID := Buffer(16), "hresult") DllCall("ShCore\CreateRandomAccessStreamOverStream" , "ptr", pStream , "uint", BSOS_PREFERDESTINATIONSTREAM := 1 , "ptr", CLSID , "ptr*", &pRandomAccessStream:=0 - ,"HRESULT") + ,"hresult") return pRandomAccessStream } @@ -3422,7 +3422,7 @@ class ImagePut { ; WICBitmapNoCache must be 1! ; IWICImagingFactory::CreateBitmap - https://github.com/iseahound/10/blob/win/10.0.16299.0/um/wincodec.h#L6447 - DllCall("ole32\CLSIDFromString", "wstr", GUID_WICPixelFormat32bppBGRA := "{6fddc324-4e03-4bfe-b185-3d77768dc90f}", "ptr", CLSID := Buffer(16), "HRESULT") + DllCall("ole32\CLSIDFromString", "wstr", GUID_WICPixelFormat32bppBGRA := "{6fddc324-4e03-4bfe-b185-3d77768dc90f}", "ptr", CLSID := Buffer(16), "hresult") ComCall(17, IWICImagingFactory, "uint", width, "uint", height, "ptr", CLSID, "int", 1, "ptr*", &wicBitmap:=0) Rect := Buffer(16, 0) ; sizeof(Rect) = 16 @@ -3454,14 +3454,14 @@ class ImagePut { static set_safeArray(pStream) { ; Allocate a one-dimensional SAFEARRAY based on the size of the stream. - DllCall("shlwapi\IStream_Size", "ptr", pStream, "uint64*", &size:=0, "HRESULT") + DllCall("shlwapi\IStream_Size", "ptr", pStream, "uint64*", &size:=0, "hresult") safeArray := ComObjArray(0x11, size) ; VT_ARRAY | VT_UI1 pvData := NumGet(ComObjValue(safeArray), 8 + A_PtrSize, "ptr") ; Copy the stream to the SAFEARRAY. - DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") - DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", pvData, "uint", size, "HRESULT") - DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "hresult") + DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", pvData, "uint", size, "hresult") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "hresult") return safeArray } @@ -3471,7 +3471,7 @@ class ImagePut { ; Create an IStream backed with movable memory. hData := DllCall("GlobalAlloc", "uint", 0x2, "uptr", 0, "ptr") - DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", True, "ptr*", &pStream:=0, "HRESULT") + DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", True, "ptr*", &pStream:=0, "hresult") ; Default extension is PNG for small sizes! (extension == "") && extension := "png" @@ -3522,7 +3522,7 @@ class ImagePut { ; clsid Image Encoder Constants - http://www.jose.it-berater.org/gdiplus/reference/constants/gdipimageencoderconstants.htm ep := Buffer(24+2*A_PtrSize) ; sizeof(EncoderParameter) = ptr + n*(28, 32) NumPut( "uptr", 1, ep, 0) ; Count - DllCall("ole32\CLSIDFromString", "wstr", "{1D5BE4B5-FA4A-452D-9CDD-5DB35105E7EB}", "ptr", ep.ptr+A_PtrSize, "HRESULT") + DllCall("ole32\CLSIDFromString", "wstr", "{1D5BE4B5-FA4A-452D-9CDD-5DB35105E7EB}", "ptr", ep.ptr+A_PtrSize, "hresult") NumPut( "uint", 1, ep, 16+A_PtrSize) ; Number of Values NumPut( "uint", 4, ep, 20+A_PtrSize) ; Type NumPut( "ptr", v.ptr, ep, 24+A_PtrSize) ; Value @@ -3530,9 +3530,9 @@ class ImagePut { } static select_extension(pStream, &extension) { - DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") - DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", signature := Buffer(256), "uint", 256, "HRESULT") - DllCall("shlwapi\IStream_Reset", "ptr", pStream, "HRESULT") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "hresult") + DllCall("shlwapi\IStream_Read", "ptr", pStream, "ptr", signature := Buffer(256), "uint", 256, "hresult") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "hresult") ; This function sniffs the first 256 bytes and matches a known file signature. ; 256 bytes is recommended, but images only need 12 bytes. @@ -3546,7 +3546,7 @@ class ImagePut { , "uint", 0x20 ; dwMimeFlags , "ptr*", &MimeOut:=0 ; ppwzMimeOut , "uint", 0 ; dwReserved - ,"HRESULT") + ,"hresult") MimeType := StrGet(MimeOut, "UTF-16") DllCall("ole32\CoTaskMemFree", "ptr", MimeOut) From 4d36be8c373163e61a01c7d8d653696ea9b11595 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 4 Feb 2023 12:56:20 -0500 Subject: [PATCH 380/492] Fix Save() failing for 2nd buffer of different size --- ImagePut (for v1).ahk | 44 ++++++++++++++++++++----------------------- ImagePut.ahk | 44 ++++++++++++++++++++----------------------- 2 files changed, 40 insertions(+), 48 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 3f8d2fb8..288b2684 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2139,30 +2139,26 @@ class ImagePut { if (extension != "bmp") return ImagePut.put_file(this.pBitmap, filepath, quality) - ; Save header info. - static bm := 0 - if !bm { - VarSetCapacity(bm, 54) - - StrPut("BM", &bm, "CP0") ; identifier - NumPut(54+this.size, bm, 2, "uint") ; file size - NumPut( 0, bm, 6, "uint") ; reserved - NumPut( 54, bm, 10, "uint") ; bitmap data offset - - ; BITMAPINFOHEADER struct - NumPut( 40, bm, 14, "uint") ; Size - NumPut( this.width, bm, 18, "uint") ; Width - NumPut(-this.height, bm, 22, "int") ; Height - Negative so (0, 0) is top-left. - NumPut( 1, bm, 26, "ushort") ; Planes - NumPut( 32, bm, 28, "ushort") ; BitCount / BitsPerPixel - - NumPut( 0, bm, 30, "uint") ; biCompression - NumPut( this.size, bm, 34, "uint") ; biSizeImage - NumPut( 0, bm, 38, "int") ; biXPelsPerMeter - NumPut( 0, bm, 42, "int") ; biYPelsPerMeter - NumPut( 0, bm, 46, "uint") ; biClrUsed - NumPut( 0, bm, 50, "uint") ; biClrImportant - } + VarSetCapacity(bm, 54) + + StrPut("BM", &bm, "CP0") ; identifier + NumPut(54+this.size, bm, 2, "uint") ; file size + NumPut( 0, bm, 6, "uint") ; reserved + NumPut( 54, bm, 10, "uint") ; bitmap data offset + + ; BITMAPINFOHEADER struct + NumPut( 40, bm, 14, "uint") ; Size + NumPut( this.width, bm, 18, "uint") ; Width + NumPut(-this.height, bm, 22, "int") ; Height - Negative so (0, 0) is top-left. + NumPut( 1, bm, 26, "ushort") ; Planes + NumPut( 32, bm, 28, "ushort") ; BitCount / BitsPerPixel + + NumPut( 0, bm, 30, "uint") ; biCompression + NumPut( this.size, bm, 34, "uint") ; biSizeImage + NumPut( 0, bm, 38, "int") ; biXPelsPerMeter + NumPut( 0, bm, 42, "int") ; biYPelsPerMeter + NumPut( 0, bm, 46, "uint") ; biClrUsed + NumPut( 0, bm, 50, "uint") ; biClrImportant loop try diff --git a/ImagePut.ahk b/ImagePut.ahk index 4144161c..1f8092bb 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2139,30 +2139,26 @@ class ImagePut { if (extension != "bmp") return ImagePut.put_file(this.pBitmap, filepath, quality) - ; Save header info. - static bm := 0 - if !bm { - bm := Buffer(54) - - StrPut("BM", bm, "CP0") ; identifier - NumPut( "uint", 54+this.size, bm, 2) ; file size - NumPut( "uint", 0, bm, 6) ; reserved - NumPut( "uint", 54, bm, 10) ; bitmap data offset - - ; BITMAPINFOHEADER struct - NumPut( "uint", 40, bm, 14) ; Size - NumPut( "uint", this.width, bm, 18) ; Width - NumPut( "int", -this.height, bm, 22) ; Height - Negative so (0, 0) is top-left. - NumPut("ushort", 1, bm, 26) ; Planes - NumPut("ushort", 32, bm, 28) ; BitCount / BitsPerPixel - - NumPut( "uint", 0, bm, 30) ; biCompression - NumPut( "uint", this.size, bm, 34) ; biSizeImage - NumPut( "int", 0, bm, 38) ; biXPelsPerMeter - NumPut( "int", 0, bm, 42) ; biYPelsPerMeter - NumPut( "uint", 0, bm, 46) ; biClrUsed - NumPut( "uint", 0, bm, 50) ; biClrImportant - } + bm := Buffer(54) + + StrPut("BM", bm, "CP0") ; identifier + NumPut( "uint", 54+this.size, bm, 2) ; file size + NumPut( "uint", 0, bm, 6) ; reserved + NumPut( "uint", 54, bm, 10) ; bitmap data offset + + ; BITMAPINFOHEADER struct + NumPut( "uint", 40, bm, 14) ; Size + NumPut( "uint", this.width, bm, 18) ; Width + NumPut( "int", -this.height, bm, 22) ; Height - Negative so (0, 0) is top-left. + NumPut("ushort", 1, bm, 26) ; Planes + NumPut("ushort", 32, bm, 28) ; BitCount / BitsPerPixel + + NumPut( "uint", 0, bm, 30) ; biCompression + NumPut( "uint", this.size, bm, 34) ; biSizeImage + NumPut( "int", 0, bm, 38) ; biXPelsPerMeter + NumPut( "int", 0, bm, 42) ; biYPelsPerMeter + NumPut( "uint", 0, bm, 46) ; biClrUsed + NumPut( "uint", 0, bm, 50) ; biClrImportant loop try From 218a8475cc24fbe42681d9f4eaadbb5c664ab287 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 4 Feb 2023 13:01:44 -0500 Subject: [PATCH 381/492] Streamline NumGet across v1/v2 --- ImagePut (for v1).ahk | 8 ++++---- ImagePut.ahk | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 288b2684..53796501 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2833,10 +2833,10 @@ class ImagePut { frame := wParam + 1 ; Get the next frame and delay. - frames := NumGet(Item+0, 4, "uint") // 4 ; Max frames - delays := NumGet(Item+0, 8 + A_PtrSize, "ptr") ; Array of delays - frame := mod(frame, frames) ; Loop to first frame - delay := max(10 * NumGet(delays+0, frame*4, "uint"), 10) ; Minimum delay is 10ms + frames := NumGet(Item + 4, "uint") // 4 ; Max frames + delays := NumGet(Item + 8 + A_PtrSize, "ptr") ; Array of delays + frame := mod(frame, frames) ; Loop to first frame + delay := max(10 * NumGet(delays + frame*4, "uint"), 10) ; Minimum delay is 10ms ; Emulate behavior of setting 10 ms to 100 ms. (delay == 10) && delay := 100 ; See: https://www.biphelps.com/blog/The-Fastest-GIF-Does-Not-Exist diff --git a/ImagePut.ahk b/ImagePut.ahk index 1f8092bb..94e90208 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2833,10 +2833,10 @@ class ImagePut { frame := wParam + 1 ; Get the next frame and delay. - frames := NumGet(Item, 4, "uint") // 4 ; Max frames - delays := NumGet(Item, 8 + A_PtrSize, "ptr") ; Array of delays - frame := mod(frame, frames) ; Loop to first frame - delay := max(10 * NumGet(delays, frame*4, "uint"), 10) ; Minimum delay is 10ms + frames := NumGet(Item + 4, "uint") // 4 ; Max frames + delays := NumGet(Item + 8 + A_PtrSize, "ptr") ; Array of delays + frame := mod(frame, frames) ; Loop to first frame + delay := max(10 * NumGet(delays + frame*4, "uint"), 10) ; Minimum delay is 10ms ; Emulate behavior of setting 10 ms to 100 ms. (delay == 10) && delay := 100 ; See: https://www.biphelps.com/blog/The-Fastest-GIF-Does-Not-Exist From 7dccca40ebffc6c6d8df3193746e0ef2cb24f8c4 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 4 Feb 2023 13:37:51 -0500 Subject: [PATCH 382/492] spacing --- ImagePut (for v1).ahk | 1 + 1 file changed, 1 insertion(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 53796501..4fe822ce 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -3632,6 +3632,7 @@ class ImagePut { + ; Startup gdiplus when counter rises from 0 -> 1. if (instances = 0 && vary = 1) { From 346e1c0a49876c125a3dbc5615f38f0202bfa82c Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 5 Feb 2023 09:31:52 -0500 Subject: [PATCH 383/492] comment --- ImagePut.ahk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index 94e90208..5c422c90 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -3630,7 +3630,7 @@ class ImagePut { static pToken := 0 ; Takes advantage of the fact that objects contain identical methods. static instances := 0 ; And therefore static variables can share data across instances. - ; Guard against __Delete() errors. + ; Guard against __Delete() errors when WindowProc is running an animated GIF. if not IsSet(pToken) || not IsSet(instances) return From ab04e519a9a8155a5cf29a003bf7b383e9e485c1 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 11 Feb 2023 13:32:43 -0500 Subject: [PATCH 384/492] Add 3 parameter variation to PixelSearch --- ImagePut (for v1).ahk | 48 ++++++++++++++++++++++++++--------------- ImagePut.ahk | 50 ++++++++++++++++++++++++++++--------------- 2 files changed, 64 insertions(+), 34 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 4fe822ce..73542733 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2279,30 +2279,16 @@ class ImagePut { ; Lift color to 32-bits if first 8 bits are zero. (color >> 24) || color |= 0xFF000000 - ; PixelSearch, range of colors, and variation. - if IsObject(variation) { - byte := DllCall(PixelSearch2, "ptr", this.ptr, "ptr", this.ptr + this.size - , "uchar", min(max(variation[1], variation[2]), 255) - , "uchar", max(min(variation[1], variation[2]), 0) - , "uchar", min(max(variation[3], variation[4]), 255) - , "uchar", max(min(variation[3], variation[4]), 0) - , "uchar", min(max(variation[5], variation[6]), 255) - , "uchar", max(min(variation[5], variation[6]), 0) - , "ptr") - } - ; PixelSearch, single color, no variation - else if (variation == 0) { - ; Get the address of the first matching pixel. + if !IsObject(variation) && (variation == 0) byte := DllCall(PixelSearch, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "ptr") - } ; PixelSearch, single color, and variation - else { - v := abs(variation) + else if !IsObject(variation) && (variation != 0) { r := ((color & 0xFF0000) >> 16) g := ((color & 0xFF00) >> 8) b := ((color & 0xFF)) + v := abs(variation) ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. byte := DllCall(PixelSearch2, "ptr", this.ptr, "ptr", this.ptr + this.size @@ -2315,6 +2301,34 @@ class ImagePut { , "ptr") } + ; PixelSearch, range of colors, and variation. + else if IsObject(variation) && (variation.length() == 3) { + r := ((color & 0xFF0000) >> 16) + g := ((color & 0xFF00) >> 8) + b := ((color & 0xFF)) + + byte := DllCall(PixelSearch2, "ptr", this.ptr, "ptr", this.ptr + this.size + , "uchar", min(r + variation[1], 255) + , "uchar", max(r - variation[1], 0) + , "uchar", min(g + variation[2], 255) + , "uchar", max(g - variation[2], 0) + , "uchar", min(b + variation[3], 255) + , "uchar", max(b - variation[3], 0) + , "ptr") + } + + ; PixelSearch, range of colors, and variation. + else if IsObject(variation) && (variation.length() == 6) { + byte := DllCall(PixelSearch2, "ptr", this.ptr, "ptr", this.ptr + this.size + , "uchar", min(max(variation[1], variation[2]), 255) + , "uchar", max(min(variation[1], variation[2]), 0) + , "uchar", min(max(variation[3], variation[4]), 255) + , "uchar", max(min(variation[3], variation[4]), 0) + , "uchar", min(max(variation[5], variation[6]), 255) + , "uchar", max(min(variation[5], variation[6]), 0) + , "ptr") + } + ; Compare the address to the out-of-bounds limit. if (byte == this.ptr + this.size) return False diff --git a/ImagePut.ahk b/ImagePut.ahk index 5c422c90..8e2cd0ad 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2279,30 +2279,16 @@ class ImagePut { ; Lift color to 32-bits if first 8 bits are zero. (color >> 24) || color |= 0xFF000000 - ; PixelSearch, range of colors, and variation. - if IsObject(variation) { - byte := DllCall(PixelSearch2, "ptr", this.ptr, "ptr", this.ptr + this.size - , "uchar", min(max(variation[1], variation[2]), 255) - , "uchar", max(min(variation[1], variation[2]), 0) - , "uchar", min(max(variation[3], variation[4]), 255) - , "uchar", max(min(variation[3], variation[4]), 0) - , "uchar", min(max(variation[5], variation[6]), 255) - , "uchar", max(min(variation[5], variation[6]), 0) - , "ptr") - } - ; PixelSearch, single color, no variation - else if (variation == 0) { - ; Get the address of the first matching pixel. + if !IsObject(variation) && (variation == 0) byte := DllCall(PixelSearch, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "ptr") - } ; PixelSearch, single color, and variation - else { - v := abs(variation) + else if !IsObject(variation) && (variation != 0) { r := ((color & 0xFF0000) >> 16) g := ((color & 0xFF00) >> 8) b := ((color & 0xFF)) + v := abs(variation) ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. byte := DllCall(PixelSearch2, "ptr", this.ptr, "ptr", this.ptr + this.size @@ -2315,6 +2301,36 @@ class ImagePut { , "ptr") } + ; PixelSearch, range of colors, and variation. + else if IsObject(variation) && (variation.length == 3) { + r := ((color & 0xFF0000) >> 16) + g := ((color & 0xFF00) >> 8) + b := ((color & 0xFF)) + + byte := DllCall(PixelSearch2, "ptr", this.ptr, "ptr", this.ptr + this.size + , "uchar", min(r + variation[1], 255) + , "uchar", max(r - variation[1], 0) + , "uchar", min(g + variation[2], 255) + , "uchar", max(g - variation[2], 0) + , "uchar", min(b + variation[3], 255) + , "uchar", max(b - variation[3], 0) + , "ptr") + } + + ; PixelSearch, range of colors, and variation. + else if IsObject(variation) && (variation.length == 6) { + byte := DllCall(PixelSearch2, "ptr", this.ptr, "ptr", this.ptr + this.size + , "uchar", min(max(variation[1], variation[2]), 255) + , "uchar", max(min(variation[1], variation[2]), 0) + , "uchar", min(max(variation[3], variation[4]), 255) + , "uchar", max(min(variation[3], variation[4]), 0) + , "uchar", min(max(variation[5], variation[6]), 255) + , "uchar", max(min(variation[5], variation[6]), 0) + , "ptr") + } + + else throw Error("Invalid variation parameter.") + ; Compare the address to the out-of-bounds limit. if (byte == this.ptr + this.size) return False From 05952b438c55c7ffd2c37eaf545be06bff17048a Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 11 Feb 2023 13:34:49 -0500 Subject: [PATCH 385/492] re-add exception --- ImagePut (for v1).ahk | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 73542733..421067a9 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2329,6 +2329,8 @@ class ImagePut { , "ptr") } + else throw Exception("Invalid variation parameter.") + ; Compare the address to the out-of-bounds limit. if (byte == this.ptr + this.size) return False From ea13e117dfe996561541dcdd5db0d3c7b7ed0ada Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 13 Feb 2023 12:01:15 -0500 Subject: [PATCH 386/492] right click to close --- demo.ahk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo.ahk b/demo.ahk index 75d0b57a..ae185b83 100644 --- a/demo.ahk +++ b/demo.ahk @@ -3,7 +3,7 @@ #singleinstance force ; Show image in window. -hwnd := ImagePutWindow("https://picsum.photos/1000/200", "Thank you for trying ImagePut ?") +hwnd := ImagePutWindow("https://picsum.photos/1000/200", "Thank you for trying ImagePut ? Right click to close") ; Save image to file. filepath := ImagePutFile("https://i.imgur.com/cCyb8bq.gif") From 63795c4fea928d2aace7c4452ff3ba26fb2c05a8 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 13 Feb 2023 15:24:52 -0500 Subject: [PATCH 387/492] Fix GIFs on 32-bit --- ImagePut (for v1).ahk | 27 +++++++++++++++------------ ImagePut.ahk | 27 +++++++++++++++------------ 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 421067a9..de3f4a09 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2727,10 +2727,11 @@ class ImagePut { DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmapClone) ; Store data inside window class extra bits (cbWndExtra). - DllCall("SetWindowLongPtr", "ptr", hwnd, "int", 0, "ptr", pBitmapClone) - DllCall("SetWindowLongPtr", "ptr", hwnd, "int", A_PtrSize, "ptr", hdc) - DllCall("SetWindowLongPtr", "ptr", hwnd, "int", 2*A_PtrSize, "ptr", Item) - DllCall("SetWindowLongPtr", "ptr", hwnd, "int", 3*A_PtrSize, "ptr", pBits) + __32 := A_PtrSize = 8 ? "Ptr" : "" ; Fixes 32-bit windows + DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 0, "ptr", pBitmapClone) + DllCall("SetWindowLong" __32, "ptr", hwnd, "int", A_PtrSize, "ptr", hdc) + DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 2*A_PtrSize, "ptr", Item) + DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 3*A_PtrSize, "ptr", pBits) ; Preserve GDI+ scope. ImagePut.gdiplusStartup() @@ -2799,12 +2800,13 @@ class ImagePut { ; WM_DESTROY if (uMsg = 0x2) { - if pBitmap := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", 0, "ptr") { - hdc := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", A_PtrSize, "ptr") - Item := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", 2*A_PtrSize, "ptr") + __32 := A_PtrSize = 8 ? "Ptr" : "" ; Fixes 32-bit windows + if pBitmap := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 0, "ptr") { + hdc := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", A_PtrSize, "ptr") + Item := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 2*A_PtrSize, "ptr") ; Exit loop. - DllCall("SetWindowLongPtr", "ptr", hwnd, "int", 0, "ptr", 0) ; Exit loop. + DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 0, "ptr", 0) ; Dispose of all data stored in the window class. DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) @@ -2841,11 +2843,12 @@ class ImagePut { Critical ; Exit Gif loop or get variables. - if !(pBitmap := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", 0, "ptr")) + __32 := A_PtrSize = 8 ? "Ptr" : "" ; Fixes 32-bit windows + if !(pBitmap := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 0, "ptr")) return - hdc := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", A_PtrSize, "ptr") - Item := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", 2*A_PtrSize, "ptr") - pBits := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", 3*A_PtrSize, "ptr") + hdc := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", A_PtrSize, "ptr") + Item := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 2*A_PtrSize, "ptr") + pBits := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 3*A_PtrSize, "ptr") frame := wParam + 1 ; Get the next frame and delay. diff --git a/ImagePut.ahk b/ImagePut.ahk index 8e2cd0ad..52f97109 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2727,10 +2727,11 @@ class ImagePut { DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmapClone) ; Store data inside window class extra bits (cbWndExtra). - DllCall("SetWindowLongPtr", "ptr", hwnd, "int", 0, "ptr", pBitmapClone) - DllCall("SetWindowLongPtr", "ptr", hwnd, "int", A_PtrSize, "ptr", hdc) - DllCall("SetWindowLongPtr", "ptr", hwnd, "int", 2*A_PtrSize, "ptr", Item) - DllCall("SetWindowLongPtr", "ptr", hwnd, "int", 3*A_PtrSize, "ptr", pBits) + __32 := A_PtrSize = 8 ? "Ptr" : "" ; Fixes 32-bit windows + DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 0, "ptr", pBitmapClone) + DllCall("SetWindowLong" __32, "ptr", hwnd, "int", A_PtrSize, "ptr", hdc) + DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 2*A_PtrSize, "ptr", Item) + DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 3*A_PtrSize, "ptr", pBits) ; Preserve GDI+ scope. ImagePut.gdiplusStartup() @@ -2799,12 +2800,13 @@ class ImagePut { ; WM_DESTROY if (uMsg = 0x2) { - if pBitmap := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", 0, "ptr") { - hdc := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", A_PtrSize, "ptr") - Item := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", 2*A_PtrSize, "ptr") + __32 := A_PtrSize = 8 ? "Ptr" : "" ; Fixes 32-bit windows + if pBitmap := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 0, "ptr") { + hdc := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", A_PtrSize, "ptr") + Item := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 2*A_PtrSize, "ptr") ; Exit loop. - DllCall("SetWindowLongPtr", "ptr", hwnd, "int", 0, "ptr", 0) + DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 0, "ptr", 0) ; Dispose of all data stored in the window class. DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) @@ -2841,11 +2843,12 @@ class ImagePut { Critical ; Exit Gif loop or get variables. - if !(pBitmap := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", 0, "ptr")) + __32 := A_PtrSize = 8 ? "Ptr" : "" ; Fixes 32-bit windows + if !(pBitmap := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 0, "ptr")) return - hdc := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", A_PtrSize, "ptr") - Item := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", 2*A_PtrSize, "ptr") - pBits := DllCall("GetWindowLongPtr", "ptr", hwnd, "int", 3*A_PtrSize, "ptr") + hdc := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", A_PtrSize, "ptr") + Item := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 2*A_PtrSize, "ptr") + pBits := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 3*A_PtrSize, "ptr") frame := wParam + 1 ; Get the next frame and delay. From f99ad58faa64ab266dfb10ac343a7dfa75290845 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 13 Feb 2023 15:39:49 -0500 Subject: [PATCH 388/492] cleanup GIF code --- ImagePut (for v1).ahk | 25 +++++++++++++++---------- ImagePut.ahk | 25 +++++++++++++++---------- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index de3f4a09..c5476550 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2842,23 +2842,28 @@ class ImagePut { ; Thanks tmplinshi, Teadrinker - https://www.autohotkey.com/boards/viewtopic.php?f=76&t=83358 Critical - ; Exit Gif loop or get variables. + ; Get variables. __32 := A_PtrSize = 8 ? "Ptr" : "" ; Fixes 32-bit windows - if !(pBitmap := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 0, "ptr")) - return + pBitmap := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 0, "ptr") hdc := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", A_PtrSize, "ptr") Item := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 2*A_PtrSize, "ptr") pBits := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 3*A_PtrSize, "ptr") - frame := wParam + 1 - ; Get the next frame and delay. + ; Exit loop. + if !pBitmap + return + + ; Get next frame. frames := NumGet(Item + 4, "uint") // 4 ; Max frames - delays := NumGet(Item + 8 + A_PtrSize, "ptr") ; Array of delays - frame := mod(frame, frames) ; Loop to first frame - delay := max(10 * NumGet(delays + frame*4, "uint"), 10) ; Minimum delay is 10ms + frame := wParam + 1 ; Next frame + frame := mod(frame, frames) ; Loop back to first frame - ; Emulate behavior of setting 10 ms to 100 ms. - (delay == 10) && delay := 100 ; See: https://www.biphelps.com/blog/The-Fastest-GIF-Does-Not-Exist + ; Get delay. + delays := NumGet(Item + 8 + A_PtrSize, "ptr") ; Array of delays + delay := 10 * NumGet(delays + 4*frame, "uint") ; Delay of next frame + delay := max(delay, 10) ; Minimum delay is 10ms + (delay == 10) && delay := 100 ; 10 ms is actually 100 ms + ; See: https://www.biphelps.com/blog/The-Fastest-GIF-Does-Not-Exist ; Randomize the delay in intervals of 15.6 resolution := 15.6 diff --git a/ImagePut.ahk b/ImagePut.ahk index 52f97109..68eefb64 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2842,23 +2842,28 @@ class ImagePut { ; Thanks tmplinshi, Teadrinker - https://www.autohotkey.com/boards/viewtopic.php?f=76&t=83358 Critical - ; Exit Gif loop or get variables. + ; Get variables. __32 := A_PtrSize = 8 ? "Ptr" : "" ; Fixes 32-bit windows - if !(pBitmap := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 0, "ptr")) - return + pBitmap := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 0, "ptr") hdc := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", A_PtrSize, "ptr") Item := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 2*A_PtrSize, "ptr") pBits := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 3*A_PtrSize, "ptr") - frame := wParam + 1 - ; Get the next frame and delay. + ; Exit loop. + if !pBitmap + return + + ; Get next frame. frames := NumGet(Item + 4, "uint") // 4 ; Max frames - delays := NumGet(Item + 8 + A_PtrSize, "ptr") ; Array of delays - frame := mod(frame, frames) ; Loop to first frame - delay := max(10 * NumGet(delays + frame*4, "uint"), 10) ; Minimum delay is 10ms + frame := wParam + 1 ; Next frame + frame := mod(frame, frames) ; Loop back to first frame - ; Emulate behavior of setting 10 ms to 100 ms. - (delay == 10) && delay := 100 ; See: https://www.biphelps.com/blog/The-Fastest-GIF-Does-Not-Exist + ; Get delay. + delays := NumGet(Item + 8 + A_PtrSize, "ptr") ; Array of delays + delay := 10 * NumGet(delays + 4*frame, "uint") ; Delay of next frame + delay := max(delay, 10) ; Minimum delay is 10ms + (delay == 10) && delay := 100 ; 10 ms is actually 100 ms + ; See: https://www.biphelps.com/blog/The-Fastest-GIF-Does-Not-Exist ; Randomize the delay in intervals of 15.6 resolution := 15.6 From c937011fde8f26124228efe9cb8cb1ba6857ddfe Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 13 Feb 2023 15:55:56 -0500 Subject: [PATCH 389/492] Refactor gifs to use addresses 1-4 of 0-4 --- ImagePut (for v1).ahk | 24 ++++++++++++------------ ImagePut.ahk | 24 ++++++++++++------------ 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index c5476550..96576ee2 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2728,10 +2728,10 @@ class ImagePut { ; Store data inside window class extra bits (cbWndExtra). __32 := A_PtrSize = 8 ? "Ptr" : "" ; Fixes 32-bit windows - DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 0, "ptr", pBitmapClone) - DllCall("SetWindowLong" __32, "ptr", hwnd, "int", A_PtrSize, "ptr", hdc) - DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 2*A_PtrSize, "ptr", Item) - DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 3*A_PtrSize, "ptr", pBits) + DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 1*A_PtrSize, "ptr", pBitmapClone) + DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 2*A_PtrSize, "ptr", hdc) + DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 3*A_PtrSize, "ptr", Item) + DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 4*A_PtrSize, "ptr", pBits) ; Preserve GDI+ scope. ImagePut.gdiplusStartup() @@ -2801,12 +2801,12 @@ class ImagePut { ; WM_DESTROY if (uMsg = 0x2) { __32 := A_PtrSize = 8 ? "Ptr" : "" ; Fixes 32-bit windows - if pBitmap := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 0, "ptr") { - hdc := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", A_PtrSize, "ptr") - Item := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 2*A_PtrSize, "ptr") + if pBitmap := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 1*A_PtrSize, "ptr") { + hdc := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 2*A_PtrSize, "ptr") + Item := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 3*A_PtrSize, "ptr") ; Exit loop. - DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 0, "ptr", 0) + DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 1*A_PtrSize, "ptr", 0) ; Dispose of all data stored in the window class. DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) @@ -2844,10 +2844,10 @@ class ImagePut { ; Get variables. __32 := A_PtrSize = 8 ? "Ptr" : "" ; Fixes 32-bit windows - pBitmap := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 0, "ptr") - hdc := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", A_PtrSize, "ptr") - Item := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 2*A_PtrSize, "ptr") - pBits := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 3*A_PtrSize, "ptr") + pBitmap := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 1*A_PtrSize, "ptr") + hdc := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 2*A_PtrSize, "ptr") + Item := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 3*A_PtrSize, "ptr") + pBits := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 4*A_PtrSize, "ptr") ; Exit loop. if !pBitmap diff --git a/ImagePut.ahk b/ImagePut.ahk index 68eefb64..baf46999 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2728,10 +2728,10 @@ class ImagePut { ; Store data inside window class extra bits (cbWndExtra). __32 := A_PtrSize = 8 ? "Ptr" : "" ; Fixes 32-bit windows - DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 0, "ptr", pBitmapClone) - DllCall("SetWindowLong" __32, "ptr", hwnd, "int", A_PtrSize, "ptr", hdc) - DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 2*A_PtrSize, "ptr", Item) - DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 3*A_PtrSize, "ptr", pBits) + DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 1*A_PtrSize, "ptr", pBitmapClone) + DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 2*A_PtrSize, "ptr", hdc) + DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 3*A_PtrSize, "ptr", Item) + DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 4*A_PtrSize, "ptr", pBits) ; Preserve GDI+ scope. ImagePut.gdiplusStartup() @@ -2801,12 +2801,12 @@ class ImagePut { ; WM_DESTROY if (uMsg = 0x2) { __32 := A_PtrSize = 8 ? "Ptr" : "" ; Fixes 32-bit windows - if pBitmap := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 0, "ptr") { - hdc := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", A_PtrSize, "ptr") - Item := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 2*A_PtrSize, "ptr") + if pBitmap := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 1*A_PtrSize, "ptr") { + hdc := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 2*A_PtrSize, "ptr") + Item := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 3*A_PtrSize, "ptr") ; Exit loop. - DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 0, "ptr", 0) + DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 1*A_PtrSize, "ptr", 0) ; Dispose of all data stored in the window class. DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) @@ -2844,10 +2844,10 @@ class ImagePut { ; Get variables. __32 := A_PtrSize = 8 ? "Ptr" : "" ; Fixes 32-bit windows - pBitmap := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 0, "ptr") - hdc := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", A_PtrSize, "ptr") - Item := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 2*A_PtrSize, "ptr") - pBits := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 3*A_PtrSize, "ptr") + pBitmap := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 1*A_PtrSize, "ptr") + hdc := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 2*A_PtrSize, "ptr") + Item := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 3*A_PtrSize, "ptr") + pBits := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 4*A_PtrSize, "ptr") ; Exit loop. if !pBitmap From 38e8783b52bc18dac5ebe16ebbf1dfe6d3b87f7a Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 13 Feb 2023 16:43:52 -0500 Subject: [PATCH 390/492] Fix rare bug where the parent window is not correctly identified --- ImagePut (for v1).ahk | 23 +++++++++++++++-------- ImagePut.ahk | 23 +++++++++++++++-------- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 96576ee2..c59d85f7 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2570,8 +2570,15 @@ class ImagePut { DllCall("SetWindowLong", "ptr", hwnd, "int", -20, "int", styleEx | WS_EX_LAYERED) DllCall("SetLayeredWindowAttributes", "ptr", hwnd, "uint", 0xF0F0F0, "uchar", 0, "int", 1) + ; Set itself as the *internal* top level window. + __32 := A_PtrSize = 8 ? "Ptr" : "" ; Fixes 32-bit windows + DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 0, "ptr", hwnd) + ; A layered child window is only available on Windows 8+. - this.show(pBitmap, title, [0, 0, w, h], WS_CHILD | WS_VISIBLE, WS_EX_LAYERED, hwnd) + hwnd_child := this.show(pBitmap, title, [0, 0, w, h], WS_CHILD | WS_VISIBLE, WS_EX_LAYERED, hwnd) + + ; Override the child's internal hwnd with the parent's hwnd. + DllCall("SetWindowLong" __32, "ptr", hwnd_child, "int", 0, "ptr", hwnd) ; Prevent empty windows from showing. DllCall("ShowWindow", "ptr", hwnd, "int", 1) @@ -2710,6 +2717,10 @@ class ImagePut { , "uint*", 0xFF << 16 | 0x01 << 24 ; *pblend , "uint", 2) ; dwFlags + ; Set itself as the *internal* top level window. + __32 := A_PtrSize = 8 ? "Ptr" : "" ; Fixes 32-bit windows + DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 0, "ptr", hwnd) + ; Check for multiple frames. DllCall("gdiplus\GdipImageGetFrameDimensionsCount", "ptr", pBitmap, "uint*", dims:=0) DllCall("gdiplus\GdipImageGetFrameDimensionsList", "ptr", pBitmap, "ptr", &dimIDs := VarSetCapacity(dimIDs, 16*dims), "uint", dims) @@ -2727,7 +2738,6 @@ class ImagePut { DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmapClone) ; Store data inside window class extra bits (cbWndExtra). - __32 := A_PtrSize = 8 ? "Ptr" : "" ; Fixes 32-bit windows DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 1*A_PtrSize, "ptr", pBitmapClone) DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 2*A_PtrSize, "ptr", hdc) DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 3*A_PtrSize, "ptr", Item) @@ -2790,6 +2800,7 @@ class ImagePut { } ; Define window behavior. WindowProc(uMsg, wParam, lParam) { + __32 := A_PtrSize = 8 ? "Ptr" : "" ; Fixes 32-bit windows hwnd := this ; Prevent the script from exiting early. static void := ObjBindMethod({}, {}) @@ -2800,7 +2811,6 @@ class ImagePut { ; WM_DESTROY if (uMsg = 0x2) { - __32 := A_PtrSize = 8 ? "Ptr" : "" ; Fixes 32-bit windows if pBitmap := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 1*A_PtrSize, "ptr") { hdc := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 2*A_PtrSize, "ptr") Item := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 3*A_PtrSize, "ptr") @@ -2824,15 +2834,13 @@ class ImagePut { ; WM_LBUTTONDOWN if (uMsg = 0x201) { - parent := DllCall("GetParent", "ptr", hwnd, "ptr") - hwnd := (parent != A_ScriptHwnd && parent != 0) ? parent : hwnd + hwnd := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 0, "ptr") ; internal parent hwnd return DllCall("DefWindowProc", "ptr", hwnd, "uint", 0xA1, "uptr", 2, "ptr", 0, "ptr") } ; WM_RBUTTONUP if (uMsg = 0x205) { - parent := DllCall("GetParent", "ptr", hwnd, "ptr") - hwnd := (parent != A_ScriptHwnd && parent != 0) ? parent : hwnd + hwnd := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 0, "ptr") ; internal parent hwnd DllCall("DestroyWindow", "ptr", hwnd) return 0 } @@ -2843,7 +2851,6 @@ class ImagePut { Critical ; Get variables. - __32 := A_PtrSize = 8 ? "Ptr" : "" ; Fixes 32-bit windows pBitmap := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 1*A_PtrSize, "ptr") hdc := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 2*A_PtrSize, "ptr") Item := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 3*A_PtrSize, "ptr") diff --git a/ImagePut.ahk b/ImagePut.ahk index baf46999..0479893d 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2570,8 +2570,15 @@ class ImagePut { DllCall("SetWindowLong", "ptr", hwnd, "int", -20, "int", styleEx | WS_EX_LAYERED) DllCall("SetLayeredWindowAttributes", "ptr", hwnd, "uint", 0xF0F0F0, "uchar", 0, "int", 1) + ; Set itself as the *internal* top level window. + __32 := A_PtrSize = 8 ? "Ptr" : "" ; Fixes 32-bit windows + DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 0, "ptr", hwnd) + ; A layered child window is only available on Windows 8+. - this.show(pBitmap, title, [0, 0, w, h], WS_CHILD | WS_VISIBLE, WS_EX_LAYERED, hwnd) + hwnd_child := this.show(pBitmap, title, [0, 0, w, h], WS_CHILD | WS_VISIBLE, WS_EX_LAYERED, hwnd) + + ; Override the child's internal hwnd with the parent's hwnd. + DllCall("SetWindowLong" __32, "ptr", hwnd_child, "int", 0, "ptr", hwnd) ; Prevent empty windows from showing. DllCall("ShowWindow", "ptr", hwnd, "int", 1) @@ -2710,6 +2717,10 @@ class ImagePut { , "uint*", 0xFF << 16 | 0x01 << 24 ; *pblend , "uint", 2) ; dwFlags + ; Set itself as the *internal* top level window. + __32 := A_PtrSize = 8 ? "Ptr" : "" ; Fixes 32-bit windows + DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 0, "ptr", hwnd) + ; Check for multiple frames. DllCall("gdiplus\GdipImageGetFrameDimensionsCount", "ptr", pBitmap, "uint*", &dims:=0) DllCall("gdiplus\GdipImageGetFrameDimensionsList", "ptr", pBitmap, "ptr", dimIDs := Buffer(16*dims), "uint", dims) @@ -2727,7 +2738,6 @@ class ImagePut { DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmapClone) ; Store data inside window class extra bits (cbWndExtra). - __32 := A_PtrSize = 8 ? "Ptr" : "" ; Fixes 32-bit windows DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 1*A_PtrSize, "ptr", pBitmapClone) DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 2*A_PtrSize, "ptr", hdc) DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 3*A_PtrSize, "ptr", Item) @@ -2790,6 +2800,7 @@ class ImagePut { ; Define window behavior. WindowProc(hwnd, uMsg, wParam, lParam) { + __32 := A_PtrSize = 8 ? "Ptr" : "" ; Fixes 32-bit windows ; Prevent the script from exiting early. static active_windows := Persistent() @@ -2800,7 +2811,6 @@ class ImagePut { ; WM_DESTROY if (uMsg = 0x2) { - __32 := A_PtrSize = 8 ? "Ptr" : "" ; Fixes 32-bit windows if pBitmap := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 1*A_PtrSize, "ptr") { hdc := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 2*A_PtrSize, "ptr") Item := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 3*A_PtrSize, "ptr") @@ -2824,15 +2834,13 @@ class ImagePut { ; WM_LBUTTONDOWN if (uMsg = 0x201) { - parent := DllCall("GetParent", "ptr", hwnd, "ptr") - hwnd := (parent != A_ScriptHwnd && parent != 0) ? parent : hwnd + hwnd := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 0, "ptr") ; internal parent hwnd return DllCall("DefWindowProc", "ptr", hwnd, "uint", 0xA1, "uptr", 2, "ptr", 0, "ptr") } ; WM_RBUTTONUP if (uMsg = 0x205) { - parent := DllCall("GetParent", "ptr", hwnd, "ptr") - hwnd := (parent != A_ScriptHwnd && parent != 0) ? parent : hwnd + hwnd := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 0, "ptr") ; internal parent hwnd DllCall("DestroyWindow", "ptr", hwnd) return 0 } @@ -2843,7 +2851,6 @@ class ImagePut { Critical ; Get variables. - __32 := A_PtrSize = 8 ? "Ptr" : "" ; Fixes 32-bit windows pBitmap := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 1*A_PtrSize, "ptr") hdc := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 2*A_PtrSize, "ptr") Item := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 3*A_PtrSize, "ptr") From ea02e39ce3af0890593dc1eec56c4f683e22859d Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 22 Feb 2023 21:04:39 -0500 Subject: [PATCH 391/492] Add CDecl to every machine code function --- ImagePut (for v1).ahk | 32 ++++++++++++++++---------------- ImagePut.ahk | 32 ++++++++++++++++---------------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index c59d85f7..b31fbe7c 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1808,7 +1808,7 @@ class ImagePut { } ; Sample the top-left pixel and set all matching pixels to be transparent. - DllCall(code, "ptr", Scan0, "ptr", Scan0 + 4*width*height, "uint", NumGet(Scan0+0, "uint")) + DllCall(code, "ptr", Scan0, "ptr", Scan0 + 4*width*height, "uint", NumGet(Scan0+0, "uint"), "cdecl") ; Write pixels to bitmap. DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", &BitmapData) @@ -2201,7 +2201,7 @@ class ImagePut { ; Set eax flag to 1 to retrieve supported CPU features. ; See this for CPU features: https://wiki.osdev.org/CPUID ; Also see page 591: https://www.amd.com/system/files/TechDocs/24594.pdf - DllCall(code, "uint*", a := 1, "uint*", b := 0, "uint*", c := 0, "uint*", d := 0) + DllCall(code, "uint*", a := 1, "uint*", b := 0, "uint*", c := 0, "uint*", d := 0, "cdecl") ; Free memory. DllCall("GlobalFree", "ptr", code) @@ -2235,7 +2235,7 @@ class ImagePut { (key == "sentinel") && key := NumGet(this.ptr, "uint") ; Replaces one ARGB color with another. - DllCall(code, "ptr", this.ptr, "uint", this.ptr + this.size, "uint", key, "uint", value) + DllCall(code, "ptr", this.ptr, "uint", this.ptr + this.size, "uint", key, "uint", value, "cdecl") } SetAlpha(alpha := 0xFF) { @@ -2246,7 +2246,7 @@ class ImagePut { : "SDnRcwpEiEEDSIPBBOvxww==") ; Sets the transparency of the entire bitmap. - DllCall(code, "ptr", this.ptr, "ptr", this.ptr + this.size, "uchar", alpha) + DllCall(code, "ptr", this.ptr, "ptr", this.ptr + this.size, "uchar", alpha, "cdecl") } TransColor(color := "sentinel", alpha := 0x00) { @@ -2260,7 +2260,7 @@ class ImagePut { (color == "sentinel") && color := NumGet(this.ptr, "uint") ; Sets the alpha value of a specified RGB color. - DllCall(code, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "uchar", alpha) + DllCall(code, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "uchar", alpha, "cdecl") } PixelSearch(color, variation := 0) { @@ -2281,7 +2281,7 @@ class ImagePut { ; PixelSearch, single color, no variation if !IsObject(variation) && (variation == 0) - byte := DllCall(PixelSearch, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "ptr") + byte := DllCall(PixelSearch, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "cdecl ptr") ; PixelSearch, single color, and variation else if !IsObject(variation) && (variation != 0) { @@ -2298,7 +2298,7 @@ class ImagePut { , "uchar", max(g-v, 0) , "uchar", min(b+v, 255) , "uchar", max(b-v, 0) - , "ptr") + , "cdecl ptr") } ; PixelSearch, range of colors, and variation. @@ -2314,7 +2314,7 @@ class ImagePut { , "uchar", max(g - variation[2], 0) , "uchar", min(b + variation[3], 255) , "uchar", max(b - variation[3], 0) - , "ptr") + , "cdecl ptr") } ; PixelSearch, range of colors, and variation. @@ -2326,7 +2326,7 @@ class ImagePut { , "uchar", max(min(variation[3], variation[4]), 0) , "uchar", min(max(variation[5], variation[6]), 255) , "uchar", max(min(variation[5], variation[6]), 0) - , "ptr") + , "cdecl ptr") } else throw Exception("Invalid variation parameter.") @@ -2353,12 +2353,12 @@ class ImagePut { ; PixelSearchAll, single color, no variation capacity := 256 VarSetCapacity(result, A_PtrSize * capacity) - count := DllCall(PixelSearch3, "ptr", &result, "uint", capacity, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "uint") + count := DllCall(PixelSearch3, "ptr", &result, "uint", capacity, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "cdecl uint") ; If the default 256 results is exceeded, run the function again. if (count > capacity) { VarSetCapacity(result, A_PtrSize * count) - count := DllCall(PixelSearch3, "ptr", &result, "uint", count, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "uint") + count := DllCall(PixelSearch3, "ptr", &result, "uint", count, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "cdecl uint") } ; Check if any matches are found. @@ -2393,7 +2393,7 @@ class ImagePut { ; Search for the address of the first matching image. byte := DllCall(code, "ptr", this.ptr, "uint", this.width, "uint", this.height - , "ptr", image.ptr, "uint", image.width, "uint", image.height, "ptr") + , "ptr", image.ptr, "uint", image.width, "uint", image.height, "cdecl ptr") ; Compare the address to the out-of-bounds limit. if (byte == this.ptr + this.size) @@ -2425,14 +2425,14 @@ class ImagePut { VarSetCapacity(result, A_PtrSize * capacity) count := DllCall(code, "ptr", &result, "uint", capacity , "ptr", this.ptr, "uint", this.width, "uint", this.height - , "ptr", image.ptr, "uint", image.width, "uint", image.height, "uint") + , "ptr", image.ptr, "uint", image.width, "uint", image.height, "cdecl uint") ; If more than 256 results, run the function with the true capacity. if (count > capacity) { VarSetCapacity(result, A_PtrSize * count) count := DllCall(code, "ptr", &result, "uint", capacity , "ptr", this.ptr, "uint", this.width, "uint", this.height - , "ptr", image.ptr, "uint", image.width, "uint", image.height, "uint") + , "ptr", image.ptr, "uint", image.width, "uint", image.height, "cdecl uint") } ; Check if any matches are found. @@ -3190,7 +3190,7 @@ class ImagePut { ; Default to lowercase hex values. Or capitalize the string below. VarSetCapacity(hex, 16) StrPut("0123456789abcdef", &hex, "CP0") - DllCall(code, "ptr", &hex, "ptr", bin, "uptr", size, "ptr", &str, "uptr", length) + DllCall(code, "ptr", &hex, "ptr", bin, "uptr", size, "ptr", &str, "uptr", length, "cdecl") ; Release binary data and stream. DllCall("GlobalUnlock", "ptr", hbin) @@ -3226,7 +3226,7 @@ class ImagePut { ; Default to lowercase hex values. Or capitalize the string below. VarSetCapacity(hex, 16) StrPut("0123456789abcdef", &hex, "CP0") - DllCall(code, "ptr", &hex, "ptr", &bin, "uptr", size, "ptr", &str, "uptr", length) + DllCall(code, "ptr", &hex, "ptr", &bin, "uptr", size, "ptr", &str, "uptr", length, "cdecl") ; Return encoded string from ANSI. return StrGet(&str, length, "CP0") diff --git a/ImagePut.ahk b/ImagePut.ahk index 0479893d..28adf0ad 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1808,7 +1808,7 @@ class ImagePut { } ; Sample the top-left pixel and set all matching pixels to be transparent. - DllCall(code, "ptr", Scan0, "ptr", Scan0 + 4*width*height, "uint", NumGet(Scan0+0, "uint")) + DllCall(code, "ptr", Scan0, "ptr", Scan0 + 4*width*height, "uint", NumGet(Scan0+0, "uint"), "cdecl") ; Write pixels to bitmap. DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", BitmapData) @@ -2201,7 +2201,7 @@ class ImagePut { ; Set eax flag to 1 to retrieve supported CPU features. ; See this for CPU features: https://wiki.osdev.org/CPUID ; Also see page 591: https://www.amd.com/system/files/TechDocs/24594.pdf - DllCall(code, "uint*", &a := 1, "uint*", &b := 0, "uint*", &c := 0, "uint*", &d := 0) + DllCall(code, "uint*", &a := 1, "uint*", &b := 0, "uint*", &c := 0, "uint*", &d := 0, "cdecl") ; Free memory. DllCall("GlobalFree", "ptr", code) @@ -2235,7 +2235,7 @@ class ImagePut { (key == "sentinel") && key := NumGet(this.ptr, "uint") ; Replaces one ARGB color with another. - DllCall(code, "ptr", this.ptr, "uint", this.ptr + this.size, "uint", key, "uint", value) + DllCall(code, "ptr", this.ptr, "uint", this.ptr + this.size, "uint", key, "uint", value, "cdecl") } SetAlpha(alpha := 0xFF) { @@ -2246,7 +2246,7 @@ class ImagePut { : "SDnRcwpEiEEDSIPBBOvxww==") ; Sets the transparency of the entire bitmap. - DllCall(code, "ptr", this.ptr, "ptr", this.ptr + this.size, "uchar", alpha) + DllCall(code, "ptr", this.ptr, "ptr", this.ptr + this.size, "uchar", alpha, "cdecl") } TransColor(color := "sentinel", alpha := 0x00) { @@ -2260,7 +2260,7 @@ class ImagePut { (color == "sentinel") && color := NumGet(this.ptr, "uint") ; Sets the alpha value of a specified RGB color. - DllCall(code, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "uchar", alpha) + DllCall(code, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "uchar", alpha, "cdecl") } PixelSearch(color, variation := 0) { @@ -2281,7 +2281,7 @@ class ImagePut { ; PixelSearch, single color, no variation if !IsObject(variation) && (variation == 0) - byte := DllCall(PixelSearch, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "ptr") + byte := DllCall(PixelSearch, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "cdecl ptr") ; PixelSearch, single color, and variation else if !IsObject(variation) && (variation != 0) { @@ -2298,7 +2298,7 @@ class ImagePut { , "uchar", max(g-v, 0) , "uchar", min(b+v, 255) , "uchar", max(b-v, 0) - , "ptr") + , "cdecl ptr") } ; PixelSearch, range of colors, and variation. @@ -2314,7 +2314,7 @@ class ImagePut { , "uchar", max(g - variation[2], 0) , "uchar", min(b + variation[3], 255) , "uchar", max(b - variation[3], 0) - , "ptr") + , "cdecl ptr") } ; PixelSearch, range of colors, and variation. @@ -2326,7 +2326,7 @@ class ImagePut { , "uchar", max(min(variation[3], variation[4]), 0) , "uchar", min(max(variation[5], variation[6]), 255) , "uchar", max(min(variation[5], variation[6]), 0) - , "ptr") + , "cdecl ptr") } else throw Error("Invalid variation parameter.") @@ -2353,12 +2353,12 @@ class ImagePut { ; PixelSearchAll, single color, no variation capacity := 256 result := Buffer(A_PtrSize * capacity) - count := DllCall(PixelSearch3, "ptr", result, "uint", capacity, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "uint") + count := DllCall(PixelSearch3, "ptr", result, "uint", capacity, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "cdecl uint") ; If the default 256 results is exceeded, run the function again. if (count > capacity) { result.size := A_PtrSize * count - count := DllCall(PixelSearch3, "ptr", result, "uint", count, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "uint") + count := DllCall(PixelSearch3, "ptr", result, "uint", count, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "cdecl uint") } ; Check if any matches are found. @@ -2393,7 +2393,7 @@ class ImagePut { ; Search for the address of the first matching image. byte := DllCall(code, "ptr", this.ptr, "uint", this.width, "uint", this.height - , "ptr", image.ptr, "uint", image.width, "uint", image.height, "ptr") + , "ptr", image.ptr, "uint", image.width, "uint", image.height, "cdecl ptr") ; Compare the address to the out-of-bounds limit. if (byte == this.ptr + this.size) @@ -2425,14 +2425,14 @@ class ImagePut { result := Buffer(A_PtrSize * capacity) count := DllCall(code, "ptr", result, "uint", capacity , "ptr", this.ptr, "uint", this.width, "uint", this.height - , "ptr", image.ptr, "uint", image.width, "uint", image.height, "uint") + , "ptr", image.ptr, "uint", image.width, "uint", image.height, "cdecl uint") ; If more than 256 results, run the function with the true capacity. if (count > capacity) { result.size := A_PtrSize * count count := DllCall(code, "ptr", result, "uint", capacity , "ptr", this.ptr, "uint", this.width, "uint", this.height - , "ptr", image.ptr, "uint", image.width, "uint", image.height, "uint") + , "ptr", image.ptr, "uint", image.width, "uint", image.height, "cdecl uint") } ; Check if any matches are found. @@ -3190,7 +3190,7 @@ class ImagePut { ; Default to lowercase hex values. Or capitalize the string below. hex := Buffer(16) StrPut("0123456789abcdef", hex, "CP0") - DllCall(code, "ptr", hex, "ptr", bin, "uptr", size, "ptr", str, "uptr", length) + DllCall(code, "ptr", hex, "ptr", bin, "uptr", size, "ptr", str, "uptr", length, "cdecl") ; Release binary data and stream. DllCall("GlobalUnlock", "ptr", hbin) @@ -3226,7 +3226,7 @@ class ImagePut { ; Default to lowercase hex values. Or capitalize the string below. hex := Buffer(16) StrPut("0123456789abcdef", hex, "CP0") - DllCall(code, "ptr", hex, "ptr", bin, "uptr", size, "ptr", str, "uptr", length) + DllCall(code, "ptr", hex, "ptr", bin, "uptr", size, "ptr", str, "uptr", length, "cdecl") ; Return encoded string from ANSI. return StrGet(str, length, "CP0") From 47b18d4f8e06d0563958a96f2c471c90ed28a1ec Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 22 Feb 2023 21:10:41 -0500 Subject: [PATCH 392/492] Add CDecl to ComCall --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index b31fbe7c..847b9930 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1361,7 +1361,7 @@ class ImagePut { throw Exception("AsyncInfo status error: " ErrorCode) } - DllCall(NumGet(NumGet(Object+0)+8*A_PtrSize), "ptr", Object, "ptr*", ObjectResult:=0) ; GetResults + DllCall(NumGet(NumGet(Object+0)+8*A_PtrSize), "ptr", Object, "ptr*", ObjectResult:=0, "cdecl") ; GetResults ObjRelease(Object) Object := ObjectResult diff --git a/ImagePut.ahk b/ImagePut.ahk index 28adf0ad..e7c19f62 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1361,7 +1361,7 @@ class ImagePut { throw Error("AsyncInfo status error: " ErrorCode) } - ComCall(8, Object, "ptr*", &ObjectResult:=0) ; GetResults + ComCall(8, Object, "ptr*", &ObjectResult:=0, "cdecl") ; GetResults ObjRelease(Object) Object := ObjectResult From b4a73b2ed14d05bcd1b224a7af327f1e051413bf Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 2 Mar 2023 15:53:14 -0500 Subject: [PATCH 393/492] v1.10 --- ImagePut (for v1).ahk | 4 ++-- ImagePut.ahk | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 847b9930..691c594b 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2,8 +2,8 @@ ; License: MIT License ; Author: Edison Hua (iseahound) ; Github: https://github.com/iseahound/ImagePut -; Date: 2022-11-06 -; Version: 1.9 +; Date: 2023-03-02 +; Version: 1.10 #Requires AutoHotkey v1.1.33+ diff --git a/ImagePut.ahk b/ImagePut.ahk index e7c19f62..ada82de1 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2,8 +2,8 @@ ; License: MIT License ; Author: Edison Hua (iseahound) ; Github: https://github.com/iseahound/ImagePut -; Date: 2022-11-06 -; Version: 1.9 +; Date: 2023-03-02 +; Version: 1.10 #Requires AutoHotkey v2.0-beta.13+ From e02bdce167b4ba2484ce63df10cd71bc669426a5 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 5 Mar 2023 22:23:15 -0500 Subject: [PATCH 394/492] rename put_XXX to to_XXX --- ImagePut (for v1).ahk | 110 +++++++++++++++++++++--------------------- ImagePut.ahk | 108 ++++++++++++++++++++--------------------- 2 files changed, 109 insertions(+), 109 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 691c594b..83b5c5ea 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -504,15 +504,15 @@ class ImagePut { BitmapToCoimage(cotype, pBitmap, p1:="", p2:="", p3:="", p4:="", p5:="", p*) { ; BitmapToCoimage("clipboard", pBitmap) if (cotype = "clipboard" || cotype = "clipboard_png") - return this.put_clipboard(pBitmap) + return this.to_clipboard(pBitmap) ; BitmapToCoimage("buffer", pBitmap) if (cotype = "buffer") - return this.put_buffer(pBitmap) + return this.to_buffer(pBitmap) ; BitmapToCoimage("screenshot", pBitmap, screenshot, alpha) if (cotype = "screenshot") - return this.put_screenshot(pBitmap, p1, p2) + return this.to_screenshot(pBitmap, p1, p2) ; BitmapToCoimage("show", pBitmap, title, pos, style, styleEx, parent) if (cotype = "show") @@ -520,51 +520,51 @@ class ImagePut { ; BitmapToCoimage("window", pBitmap, title, pos, style, styleEx, parent) if (cotype = "window") - return this.put_window(pBitmap, p1, p2, p3, p4, p5) + return this.to_window(pBitmap, p1, p2, p3, p4, p5) ; BitmapToCoimage("desktop", pBitmap) if (cotype = "desktop") - return this.put_desktop(pBitmap) + return this.to_desktop(pBitmap) ; BitmapToCoimage("wallpaper", pBitmap) if (cotype = "wallpaper") - return this.put_wallpaper(pBitmap) + return this.to_wallpaper(pBitmap) ; BitmapToCoimage("cursor", pBitmap, xHotspot, yHotspot) if (cotype = "cursor") - return this.put_cursor(pBitmap, p1, p2) + return this.to_cursor(pBitmap, p1, p2) ; BitmapToCoimage("url", pBitmap) if (cotype = "url") - return this.put_url(pBitmap) + return this.to_url(pBitmap) ; BitmapToCoimage("file", pBitmap, filepath, quality) if (cotype = "file") - return this.put_file(pBitmap, p1, p2) + return this.to_file(pBitmap, p1, p2) ; BitmapToCoimage("hex", pBitmap, extension, quality) if (cotype = "hex") - return this.put_hex(pBitmap, p1, p2) + return this.to_hex(pBitmap, p1, p2) ; BitmapToCoimage("base64", pBitmap, extension, quality) if (cotype = "base64") - return this.put_base64(pBitmap, p1, p2) + return this.to_base64(pBitmap, p1, p2) ; BitmapToCoimage("uri", pBitmap, extension, quality) if (cotype = "uri") - return this.put_uri(pBitmap, p1, p2) + return this.to_uri(pBitmap, p1, p2) ; BitmapToCoimage("dc", pBitmap, alpha) if (cotype = "dc") - return this.put_dc(pBitmap, p1) + return this.to_dc(pBitmap, p1) ; BitmapToCoimage("hBitmap", pBitmap, alpha) if (cotype = "hBitmap") - return this.put_hBitmap(pBitmap, p1) + return this.to_hBitmap(pBitmap, p1) ; BitmapToCoimage("hIcon", pBitmap) if (cotype = "hIcon") - return this.put_hIcon(pBitmap) + return this.to_hIcon(pBitmap) ; BitmapToCoimage("bitmap", pBitmap) if (cotype = "bitmap") @@ -572,27 +572,27 @@ class ImagePut { ; BitmapToCoimage("stream", pBitmap, extension, quality) if (cotype = "stream") - return this.put_stream(pBitmap, p1, p2) + return this.to_stream(pBitmap, p1, p2) ; BitmapToCoimage("RandomAccessStream", pBitmap, extension, quality) if (cotype = "RandomAccessStream") - return this.put_RandomAccessStream(pBitmap, p1, p2) + return this.to_RandomAccessStream(pBitmap, p1, p2) ; BitmapToCoimage("wicBitmap", pBitmap) if (cotype = "wicBitmap") - return this.put_wicBitmap(pBitmap) + return this.to_wicBitmap(pBitmap) ; BitmapToCoimage("explorer", pBitmap, default) if (cotype = "explorer") - return this.put_explorer(pBitmap, p1) + return this.to_explorer(pBitmap, p1) ; BitmapToCoimage("safeArray", pBitmap, extension, quality) if (cotype = "safeArray") - return this.put_safeArray(pBitmap, p1, p2) + return this.to_safeArray(pBitmap, p1, p2) ; BitmapToCoimage("formData", pBitmap, boundary, extension, quality) if (cotype = "formData") - return this.put_formData(pBitmap, p1, p2, p3) + return this.to_formData(pBitmap, p1, p2, p3) throw Exception("Conversion from bitmap to " cotype " is not supported.") } @@ -823,7 +823,7 @@ class ImagePut { Sleep (2**(A_Index-1) * 30) else throw Exception("Clipboard could not be opened.") - ; Fallback to CF_BITMAP. This format does not support transparency even with put_hBitmap(). + ; Fallback to CF_BITMAP. This format does not support transparency even with to_hBitmap(). if !DllCall("IsClipboardFormatAvailable", "uint", 2) throw Exception("Clipboard does not have CF_BITMAP data.") @@ -1816,7 +1816,7 @@ class ImagePut { return pBitmap } - put_clipboard(pBitmap) { + to_clipboard(pBitmap) { ; Standard Clipboard Formats - https://www.codeproject.com/Reference/1091137/Windows-Clipboard-Formats ; Synthesized Clipboard Formats - https://docs.microsoft.com/en-us/windows/win32/dataxchg/clipboard-formats @@ -1887,7 +1887,7 @@ class ImagePut { if !(extension ~= "gif|png") { DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", pBitmap:=0) - this.put_clipboard(pBitmap) + this.to_clipboard(pBitmap) DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) return "" } @@ -1917,7 +1917,7 @@ class ImagePut { return "" } - put_buffer(pBitmap) { + to_buffer(pBitmap) { ; Get Bitmap width and height. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) @@ -2120,12 +2120,12 @@ class ImagePut { Crop(x, y, w, h) { DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", this.pBitmap, "int*", format:=0) DllCall("gdiplus\GdipCloneBitmapAreaI", "int", x, "int", y, "int", w, "int", h, "int", format, "ptr", this.pBitmap, "ptr*", pBitmap:=0) - return ImagePut.put_buffer(pBitmap) + return ImagePut.to_buffer(pBitmap) } Show(window_border := False, title := "", pos := "", style := "", styleEx := "", parent := "") { return (window_border) - ? ImagePut.put_window(this.pBitmap, title, pos, style, styleEx, parent) + ? ImagePut.to_window(this.pBitmap, title, pos, style, styleEx, parent) : ImagePut.show(this.pBitmap, title, pos, style, styleEx, parent) } @@ -2135,9 +2135,9 @@ class ImagePut { extension := "bmp" ImagePut.select_filepath(filepath, extension) - ; If extension is not .bmp, use put_file routine. + ; If extension is not .bmp, use to_file routine. if (extension != "bmp") - return ImagePut.put_file(this.pBitmap, filepath, quality) + return ImagePut.to_file(this.pBitmap, filepath, quality) VarSetCapacity(bm, 54) @@ -2451,7 +2451,7 @@ class ImagePut { } } - put_screenshot(pBitmap, screenshot := "", alpha := "") { + to_screenshot(pBitmap, screenshot := "", alpha := "") { ; Get Bitmap width and height. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) @@ -2463,7 +2463,7 @@ class ImagePut { ; Convert the Bitmap to a hBitmap and associate a device context for blitting. hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") - hbm := this.put_hBitmap(pBitmap, alpha) + hbm := this.to_hBitmap(pBitmap, alpha) obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") ; Retrieve the device context for the screen. @@ -2489,7 +2489,7 @@ class ImagePut { return [x,y,w,h] } - put_window(pBitmap, title := "", pos := "", style := 0x82C80000, styleEx := 0x9, parent := "") { + to_window(pBitmap, title := "", pos := "", style := 0x82C80000, styleEx := 0x9, parent := "") { ; Window Styles - https://docs.microsoft.com/en-us/windows/win32/winmsg/window-styles ; Extended Window Styles - https://docs.microsoft.com/en-us/windows/win32/winmsg/extended-window-styles @@ -2952,7 +2952,7 @@ class ImagePut { } - put_desktop(pBitmap) { + to_desktop(pBitmap) { ; Thanks Gerald Degeneve - https://www.codeproject.com/Articles/856020/Draw-Behind-Desktop-Icons-in-Windows-plus ; Get Bitmap width and height. @@ -2961,7 +2961,7 @@ class ImagePut { ; Convert the Bitmap to a hBitmap and associate a device context for blitting. hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") - hbm := this.put_hBitmap(pBitmap) + hbm := this.to_hBitmap(pBitmap) obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") ; Post-Creator's Update Windows 10. WM_SPAWN_WORKER = 0x052C @@ -3003,9 +3003,9 @@ class ImagePut { return "desktop" } - put_wallpaper(pBitmap) { + to_wallpaper(pBitmap) { ; Create a temporary image file. - filepath := this.put_file(pBitmap) + filepath := this.to_file(pBitmap) ; Get the absolute path of the file. length := DllCall("GetFullPathName", "str", filepath, "uint", 0, "ptr", 0, "ptr", 0, "uint") @@ -3031,7 +3031,7 @@ class ImagePut { return "wallpaper" } - put_cursor(pBitmap, xHotspot := "", yHotspot := "") { + to_cursor(pBitmap, xHotspot := "", yHotspot := "") { ; Thanks Nick - https://stackoverflow.com/a/550965 ; Creates an icon that can be used as a cursor. @@ -3066,7 +3066,7 @@ class ImagePut { return "A_Cursor" } - put_explorer(pBitmap, default := "") { + to_explorer(pBitmap, default := "") { ; Default directory to desktop. (default == "") && default := A_Desktop @@ -3088,7 +3088,7 @@ class ImagePut { else directory := default - return this.put_file(pBitmap, directory) + return this.to_file(pBitmap, directory) } set_explorer(pStream, default := "") { @@ -3113,10 +3113,10 @@ class ImagePut { else directory := default - return this.put_file(pStream, directory) + return this.to_file(pStream, directory) } - put_file(pBitmap, filepath := "", quality := "") { + to_file(pBitmap, filepath := "", quality := "") { ; Thanks tic - https://www.autohotkey.com/boards/viewtopic.php?t=6517 extension := "png" this.select_filepath(filepath, extension) @@ -3157,14 +3157,14 @@ class ImagePut { return filepath } - put_hex(pBitmap, extension := "", quality := "") { + to_hex(pBitmap, extension := "", quality := "") { ; Thanks noname - https://www.autohotkey.com/boards/viewtopic.php?style=7&p=144247#p144247 ; Default extension is PNG for small sizes! if (extension == "") extension := "png" - pStream := this.put_stream(pBitmap, extension, quality) + pStream := this.to_stream(pBitmap, extension, quality) ; Get a pointer to binary data. DllCall("ole32\GetHGlobalFromStream", "ptr", pStream, "ptr*", hbin:=0, "uint") @@ -3232,14 +3232,14 @@ class ImagePut { return StrGet(&str, length, "CP0") } - put_base64(pBitmap, extension := "", quality := "") { + to_base64(pBitmap, extension := "", quality := "") { ; Thanks noname - https://www.autohotkey.com/boards/viewtopic.php?style=7&p=144247#p144247 ; Default extension is PNG for small sizes! if (extension == "") extension := "png" - pStream := this.put_stream(pBitmap, extension, quality) + pStream := this.to_stream(pBitmap, extension, quality) ; Get a pointer to binary data. DllCall("ole32\GetHGlobalFromStream", "ptr", pStream, "ptr*", hbin:=0, "uint") @@ -3281,12 +3281,12 @@ class ImagePut { return StrGet(&str, length, "CP0") } - put_uri(pBitmap, extension := "", quality := "") { + to_uri(pBitmap, extension := "", quality := "") { static dict := { bmp: "bmp", dib: "bmp", rle: "bmp", jpg: "jpeg", jpeg: "jpeg", jpe: "jpeg" , jfif: "jpeg", gif: "gif", tif: "tiff", tiff: "tiff", png: "png" } extension := RegExReplace(extension, "^\*?\.?") - return "data:image/" dict[extension] ";base64," this.put_base64(pBitmap, extension, quality) + return "data:image/" dict[extension] ";base64," this.to_base64(pBitmap, extension, quality) } set_uri(pStream) { @@ -3313,7 +3313,7 @@ class ImagePut { return "data:" MimeType ";base64," this.set_base64(pStream) } - put_dc(pBitmap, alpha := "") { + to_dc(pBitmap, alpha := "") { ; Revert to built in functionality if a replacement color is declared. if (alpha != "") { ; This built-in version is about 25% slower and also preserves transparency. DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", "ptr", pBitmap, "ptr*", hbm:=0, "uint", alpha) @@ -3356,7 +3356,7 @@ class ImagePut { return hdc } - put_hBitmap(pBitmap, alpha := "") { + to_hBitmap(pBitmap, alpha := "") { ; Revert to built in functionality if a replacement color is declared. if (alpha != "") { ; This built-in version is about 25% slower and also preserves transparency. DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", "ptr", pBitmap, "ptr*", hbm:=0, "uint", alpha) @@ -3401,12 +3401,12 @@ class ImagePut { return hbm } - put_hIcon(pBitmap) { + to_hIcon(pBitmap) { DllCall("gdiplus\GdipCreateHICONFromBitmap", "ptr", pBitmap, "ptr*", hIcon:=0) return hIcon } - put_stream(pBitmap, extension := "", quality := "") { + to_stream(pBitmap, extension := "", quality := "") { ; Default extension is TIF for fast speeds! if (extension == "") extension := "tif" @@ -3420,8 +3420,8 @@ class ImagePut { return pStream } - put_RandomAccessStream(pBitmap, extension := "", quality := "") { - pStream := this.put_stream(pBitmap, extension, quality) + to_RandomAccessStream(pBitmap, extension := "", quality := "") { + pStream := this.to_stream(pBitmap, extension, quality) pRandomAccessStream := this.set_RandomAccessStream(pStream) ObjRelease(pStream) ; Decrement the reference count of the IStream interface. return pRandomAccessStream @@ -3439,7 +3439,7 @@ class ImagePut { return pRandomAccessStream } - put_wicBitmap(pBitmap) { + to_wicBitmap(pBitmap) { ; Get Bitmap width and height. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) @@ -3493,7 +3493,7 @@ class ImagePut { return safeArray } - put_safeArray(pBitmap, extension := "", quality := "") { + to_safeArray(pBitmap, extension := "", quality := "") { ; Thanks tmplinshi - https://www.autohotkey.com/boards/viewtopic.php?p=354007#p354007 ; Create an IStream backed with movable memory. diff --git a/ImagePut.ahk b/ImagePut.ahk index ada82de1..de4a0f72 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -504,15 +504,15 @@ class ImagePut { static BitmapToCoimage(cotype, pBitmap, p1:="", p2:="", p3:="", p4:="", p5:="", p*) { ; BitmapToCoimage("clipboard", pBitmap) if (cotype = "clipboard" || cotype = "clipboard_png") - return this.put_clipboard(pBitmap) + return this.to_clipboard(pBitmap) ; BitmapToCoimage("buffer", pBitmap) if (cotype = "buffer") - return this.put_buffer(pBitmap) + return this.to_buffer(pBitmap) ; BitmapToCoimage("screenshot", pBitmap, screenshot, alpha) if (cotype = "screenshot") - return this.put_screenshot(pBitmap, p1, p2) + return this.to_screenshot(pBitmap, p1, p2) ; BitmapToCoimage("show", pBitmap, title, pos, style, styleEx, parent) if (cotype = "show") @@ -520,51 +520,51 @@ class ImagePut { ; BitmapToCoimage("window", pBitmap, title, pos, style, styleEx, parent) if (cotype = "window") - return this.put_window(pBitmap, p1, p2, p3, p4, p5) + return this.to_window(pBitmap, p1, p2, p3, p4, p5) ; BitmapToCoimage("desktop", pBitmap) if (cotype = "desktop") - return this.put_desktop(pBitmap) + return this.to_desktop(pBitmap) ; BitmapToCoimage("wallpaper", pBitmap) if (cotype = "wallpaper") - return this.put_wallpaper(pBitmap) + return this.to_wallpaper(pBitmap) ; BitmapToCoimage("cursor", pBitmap, xHotspot, yHotspot) if (cotype = "cursor") - return this.put_cursor(pBitmap, p1, p2) + return this.to_cursor(pBitmap, p1, p2) ; BitmapToCoimage("url", pBitmap) if (cotype = "url") - return this.put_url(pBitmap) + return this.to_url(pBitmap) ; BitmapToCoimage("file", pBitmap, filepath, quality) if (cotype = "file") - return this.put_file(pBitmap, p1, p2) + return this.to_file(pBitmap, p1, p2) ; BitmapToCoimage("hex", pBitmap, extension, quality) if (cotype = "hex") - return this.put_hex(pBitmap, p1, p2) + return this.to_hex(pBitmap, p1, p2) ; BitmapToCoimage("base64", pBitmap, extension, quality) if (cotype = "base64") - return this.put_base64(pBitmap, p1, p2) + return this.to_base64(pBitmap, p1, p2) ; BitmapToCoimage("uri", pBitmap, extension, quality) if (cotype = "uri") - return this.put_uri(pBitmap, p1, p2) + return this.to_uri(pBitmap, p1, p2) ; BitmapToCoimage("dc", pBitmap, alpha) if (cotype = "dc") - return this.put_dc(pBitmap, p1) + return this.to_dc(pBitmap, p1) ; BitmapToCoimage("hBitmap", pBitmap, alpha) if (cotype = "hBitmap") - return this.put_hBitmap(pBitmap, p1) + return this.to_hBitmap(pBitmap, p1) ; BitmapToCoimage("hIcon", pBitmap) if (cotype = "hIcon") - return this.put_hIcon(pBitmap) + return this.to_hIcon(pBitmap) ; BitmapToCoimage("bitmap", pBitmap) if (cotype = "bitmap") @@ -572,27 +572,27 @@ class ImagePut { ; BitmapToCoimage("stream", pBitmap, extension, quality) if (cotype = "stream") - return this.put_stream(pBitmap, p1, p2) + return this.to_stream(pBitmap, p1, p2) ; BitmapToCoimage("RandomAccessStream", pBitmap, extension, quality) if (cotype = "RandomAccessStream") - return this.put_RandomAccessStream(pBitmap, p1, p2) + return this.to_RandomAccessStream(pBitmap, p1, p2) ; BitmapToCoimage("wicBitmap", pBitmap) if (cotype = "wicBitmap") - return this.put_wicBitmap(pBitmap) + return this.to_wicBitmap(pBitmap) ; BitmapToCoimage("explorer", pBitmap, default) if (cotype = "explorer") - return this.put_explorer(pBitmap, p1) + return this.to_explorer(pBitmap, p1) ; BitmapToCoimage("safeArray", pBitmap, extension, quality) if (cotype = "safeArray") - return this.put_safeArray(pBitmap, p1, p2) + return this.to_safeArray(pBitmap, p1, p2) ; BitmapToCoimage("formData", pBitmap, boundary, extension, quality) if (cotype = "formData") - return this.put_formData(pBitmap, p1, p2, p3) + return this.to_formData(pBitmap, p1, p2, p3) throw Error("Conversion from bitmap to " cotype " is not supported.") } @@ -823,7 +823,7 @@ class ImagePut { Sleep (2**(A_Index-1) * 30) else throw Error("Clipboard could not be opened.") - ; Fallback to CF_BITMAP. This format does not support transparency even with put_hBitmap(). + ; Fallback to CF_BITMAP. This format does not support transparency even with to_hBitmap(). if !DllCall("IsClipboardFormatAvailable", "uint", 2) throw Error("Clipboard does not have CF_BITMAP data.") @@ -1816,7 +1816,7 @@ class ImagePut { return pBitmap } - static put_clipboard(pBitmap) { + static to_clipboard(pBitmap) { ; Standard Clipboard Formats - https://www.codeproject.com/Reference/1091137/Windows-Clipboard-Formats ; Synthesized Clipboard Formats - https://docs.microsoft.com/en-us/windows/win32/dataxchg/clipboard-formats @@ -1887,7 +1887,7 @@ class ImagePut { if !(extension ~= "gif|png") { DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr", pStream, "ptr*", &pBitmap:=0) - this.put_clipboard(pBitmap) + this.to_clipboard(pBitmap) DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) return ClipboardAll() } @@ -1917,7 +1917,7 @@ class ImagePut { return ClipboardAll() } - static put_buffer(pBitmap) { + static to_buffer(pBitmap) { ; Get Bitmap width and height. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) @@ -2120,12 +2120,12 @@ class ImagePut { Crop(x, y, w, h) { DllCall("gdiplus\GdipGetImagePixelFormat", "ptr", this.pBitmap, "int*", &format:=0) DllCall("gdiplus\GdipCloneBitmapAreaI", "int", x, "int", y, "int", w, "int", h, "int", format, "ptr", this.pBitmap, "ptr*", &pBitmap:=0) - return ImagePut.put_buffer(pBitmap) + return ImagePut.to_buffer(pBitmap) } Show(window_border := False, title := "", pos := "", style := "", styleEx := "", parent := "") { return (window_border) - ? ImagePut.put_window(this.pBitmap, title, pos, style, styleEx, parent) + ? ImagePut.to_window(this.pBitmap, title, pos, style, styleEx, parent) : ImagePut.show(this.pBitmap, title, pos, style, styleEx, parent) } @@ -2135,9 +2135,9 @@ class ImagePut { extension := "bmp" ImagePut.select_filepath(&filepath, &extension) - ; If extension is not .bmp, use put_file routine. + ; If extension is not .bmp, use to_file routine. if (extension != "bmp") - return ImagePut.put_file(this.pBitmap, filepath, quality) + return ImagePut.to_file(this.pBitmap, filepath, quality) bm := Buffer(54) @@ -2451,7 +2451,7 @@ class ImagePut { } } - static put_screenshot(pBitmap, screenshot := "", alpha := "") { + static to_screenshot(pBitmap, screenshot := "", alpha := "") { ; Get Bitmap width and height. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) @@ -2463,7 +2463,7 @@ class ImagePut { ; Convert the Bitmap to a hBitmap and associate a device context for blitting. hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") - hbm := this.put_hBitmap(pBitmap, alpha) + hbm := this.to_hBitmap(pBitmap, alpha) obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") ; Retrieve the device context for the screen. @@ -2489,7 +2489,7 @@ class ImagePut { return [x,y,w,h] } - static put_window(pBitmap, title := "", pos := "", style := 0x82C80000, styleEx := 0x9, parent := "") { + static to_window(pBitmap, title := "", pos := "", style := 0x82C80000, styleEx := 0x9, parent := "") { ; Window Styles - https://docs.microsoft.com/en-us/windows/win32/winmsg/window-styles ; Extended Window Styles - https://docs.microsoft.com/en-us/windows/win32/winmsg/extended-window-styles @@ -2952,7 +2952,7 @@ class ImagePut { } } - static put_desktop(pBitmap) { + static to_desktop(pBitmap) { ; Thanks Gerald Degeneve - https://www.codeproject.com/Articles/856020/Draw-Behind-Desktop-Icons-in-Windows-plus ; Get Bitmap width and height. @@ -2961,7 +2961,7 @@ class ImagePut { ; Convert the Bitmap to a hBitmap and associate a device context for blitting. hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") - hbm := this.put_hBitmap(pBitmap) + hbm := this.to_hBitmap(pBitmap) obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr") ; Post-Creator's Update Windows 10. WM_SPAWN_WORKER = 0x052C @@ -3003,9 +3003,9 @@ class ImagePut { return "desktop" } - static put_wallpaper(pBitmap) { + static to_wallpaper(pBitmap) { ; Create a temporary image file. - filepath := this.put_file(pBitmap) + filepath := this.to_file(pBitmap) ; Get the absolute path of the file. length := DllCall("GetFullPathName", "str", filepath, "uint", 0, "ptr", 0, "ptr", 0, "uint") @@ -3031,7 +3031,7 @@ class ImagePut { return "wallpaper" } - static put_cursor(pBitmap, xHotspot := "", yHotspot := "") { + static to_cursor(pBitmap, xHotspot := "", yHotspot := "") { ; Thanks Nick - https://stackoverflow.com/a/550965 ; Creates an icon that can be used as a cursor. @@ -3066,7 +3066,7 @@ class ImagePut { return "A_Cursor" } - static put_explorer(pBitmap, default := "") { + static to_explorer(pBitmap, default := "") { ; Default directory to desktop. (default == "") && default := A_Desktop @@ -3088,7 +3088,7 @@ class ImagePut { else directory := default - return this.put_file(pBitmap, directory) + return this.to_file(pBitmap, directory) } static set_explorer(pStream, default := "") { @@ -3116,7 +3116,7 @@ class ImagePut { return this.set_file(pStream, directory) } - static put_file(pBitmap, filepath := "", quality := "") { + static to_file(pBitmap, filepath := "", quality := "") { ; Thanks tic - https://www.autohotkey.com/boards/viewtopic.php?t=6517 extension := "png" this.select_filepath(&filepath, &extension) @@ -3157,14 +3157,14 @@ class ImagePut { return filepath } - static put_hex(pBitmap, extension := "", quality := "") { + static to_hex(pBitmap, extension := "", quality := "") { ; Thanks noname - https://www.autohotkey.com/boards/viewtopic.php?style=7&p=144247#p144247 ; Default extension is PNG for small sizes! if (extension == "") extension := "png" - pStream := this.put_stream(pBitmap, extension, quality) + pStream := this.to_stream(pBitmap, extension, quality) ; Get a pointer to binary data. DllCall("ole32\GetHGlobalFromStream", "ptr", pStream, "ptr*", &hbin:=0, "hresult") @@ -3232,14 +3232,14 @@ class ImagePut { return StrGet(str, length, "CP0") } - static put_base64(pBitmap, extension := "", quality := "") { + static to_base64(pBitmap, extension := "", quality := "") { ; Thanks noname - https://www.autohotkey.com/boards/viewtopic.php?style=7&p=144247#p144247 ; Default extension is PNG for small sizes! if (extension == "") extension := "png" - pStream := this.put_stream(pBitmap, extension, quality) + pStream := this.to_stream(pBitmap, extension, quality) ; Get a pointer to binary data. DllCall("ole32\GetHGlobalFromStream", "ptr", pStream, "ptr*", &hbin:=0, "hresult") @@ -3281,12 +3281,12 @@ class ImagePut { return StrGet(str, length, "CP0") } - static put_uri(pBitmap, extension := "", quality := "") { + static to_uri(pBitmap, extension := "", quality := "") { static dict := Map("bmp", "bmp", "dib", "bmp", "rle", "bmp", "jpg", "jpeg", "jpeg", "jpeg", "jpe", "jpeg" , "jfif", "jpeg", "gif", "gif", "tif", "tiff", "tiff", "tiff", "png", "png") extension := RegExReplace(extension, "^\*?\.?") - return "data:image/" dict[StrLower(extension)] ";base64," this.put_base64(pBitmap, extension, quality) + return "data:image/" dict[StrLower(extension)] ";base64," this.to_base64(pBitmap, extension, quality) } static set_uri(pStream) { @@ -3313,7 +3313,7 @@ class ImagePut { return "data:" MimeType ";base64," this.set_base64(pStream) } - static put_dc(pBitmap, alpha := "") { + static to_dc(pBitmap, alpha := "") { ; Revert to built in functionality if a replacement color is declared. if (alpha != "") { ; This built-in version is about 25% slower and also preserves transparency. DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", "ptr", pBitmap, "ptr*", &hbm:=0, "uint", alpha) @@ -3356,7 +3356,7 @@ class ImagePut { return hdc } - static put_hBitmap(pBitmap, alpha := "") { + static to_hBitmap(pBitmap, alpha := "") { ; Revert to built in functionality if a replacement color is declared. if (alpha != "") { ; This built-in version is about 25% slower and also preserves transparency. DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", "ptr", pBitmap, "ptr*", &hbm:=0, "uint", alpha) @@ -3401,12 +3401,12 @@ class ImagePut { return hbm } - static put_hIcon(pBitmap) { + static to_hIcon(pBitmap) { DllCall("gdiplus\GdipCreateHICONFromBitmap", "ptr", pBitmap, "ptr*", &hIcon:=0) return hIcon } - static put_stream(pBitmap, extension := "", quality := "") { + static to_stream(pBitmap, extension := "", quality := "") { ; Default extension is TIF for fast speeds! if (extension == "") extension := "tif" @@ -3420,8 +3420,8 @@ class ImagePut { return pStream } - static put_RandomAccessStream(pBitmap, extension := "", quality := "") { - pStream := this.put_stream(pBitmap, extension, quality) + static to_RandomAccessStream(pBitmap, extension := "", quality := "") { + pStream := this.to_stream(pBitmap, extension, quality) pRandomAccessStream := this.set_RandomAccessStream(pStream) ObjRelease(pStream) ; Decrement the reference count of the IStream interface. return pRandomAccessStream @@ -3439,7 +3439,7 @@ class ImagePut { return pRandomAccessStream } - static put_wicBitmap(pBitmap) { + static to_wicBitmap(pBitmap) { ; Get Bitmap width and height. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) @@ -3493,7 +3493,7 @@ class ImagePut { return safeArray } - static put_safeArray(pBitmap, extension := "", quality := "") { + static to_safeArray(pBitmap, extension := "", quality := "") { ; Thanks tmplinshi - https://www.autohotkey.com/boards/viewtopic.php?p=354007#p354007 ; Create an IStream backed with movable memory. From 4538df85375353aa4289cd2d9fde2c5085a7f27a Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 26 Mar 2023 12:23:19 -0400 Subject: [PATCH 395/492] reorder window and screenshot --- ImagePut (for v1).ahk | 8 ++++---- ImagePut.ahk | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 83b5c5ea..ac73788d 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -326,13 +326,13 @@ class ImagePut { if image.HasKey("ptr") && image.HasKey("size") return "buffer" - ; A "screenshot" is an array of 4 numbers. - if (image[1] ~= "^-?\d+$" && image[2] ~= "^-?\d+$" && image[3] ~= "^-?\d+$" && image[4] ~= "^-?\d+$") - return "screenshot" - ; A "window" is an object with an hwnd property. if image.HasKey("hwnd") return "window" + + ; A "screenshot" is an array of 4 numbers. + if (image[1] ~= "^-?\d+$" && image[2] ~= "^-?\d+$" && image[3] ~= "^-?\d+$" && image[4] ~= "^-?\d+$") + return "screenshot" } SysGet MonitorGetCount, MonitorCount ; A non-zero "monitor" number identifies each display uniquely; and 0 refers to the entire virtual screen. if (image ~= "^\d+$" && image >= 0 && image <= MonitorGetCount) diff --git a/ImagePut.ahk b/ImagePut.ahk index de4a0f72..1e71a19a 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -325,14 +325,14 @@ class ImagePut { ; A "buffer" is an object with ptr and size properties. if image.HasOwnProp("ptr") && image.HasOwnProp("size") return "buffer" + + ; A "window" is an object with an hwnd property. + if image.HasOwnProp("hwnd") + return "window" ; A "screenshot" is an array of 4 numbers. if (image[1] ~= "^-?\d+$" && image[2] ~= "^-?\d+$" && image[3] ~= "^-?\d+$" && image[4] ~= "^-?\d+$") return "screenshot" - - ; A "window" is an object with an hwnd property. - if image.HasOwnProp("hwnd") - return "window" } ; A non-zero "monitor" number identifies each display uniquely; and 0 refers to the entire virtual screen. if (image ~= "^\d+$" && image >= 0 && image <= MonitorGetCount()) From 914e7a55572efebae6fca34de2c355b3afe2dba5 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 26 Mar 2023 12:51:48 -0400 Subject: [PATCH 396/492] Screenshot Windows --- ImagePut (for v1).ahk | 20 ++++++++++++++++++++ ImagePut.ahk | 22 +++++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index ac73788d..aa9c8ebc 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -330,6 +330,10 @@ class ImagePut { if image.HasKey("hwnd") return "window" + ; A "window2" is an array with a string that contains the window title. + if (image.HasKey(1) && WinExist(image[1])) + return "window2" + ; A "screenshot" is an array of 4 numbers. if (image[1] ~= "^-?\d+$" && image[2] ~= "^-?\d+$" && image[3] ~= "^-?\d+$" && image[4] ~= "^-?\d+$") return "screenshot" @@ -447,6 +451,9 @@ class ImagePut { if (type = "window") return this.from_window(image) + if (type = "window2") + return this.from_screenshot(image[1]) + if (type = "desktop") return this.from_desktop() @@ -1092,6 +1099,19 @@ class ImagePut { from_screenshot(image) { ; Thanks tic - https://www.autohotkey.com/boards/viewtopic.php?t=6517 + if !IsObject(image) { + image := WinExist(image) + DllCall("GetWindowRect", "ptr", image, "ptr", &rect := VarSetCapacity(rect, 16)) + + if DllCall("IsIconic", "ptr", image) + DllCall("ShowWindow", "ptr", image, "int", 4) + + image := [NumGet(rect, 0, "int") + , NumGet(rect, 4, "int") + , NumGet(rect, 8, "int") - NumGet(rect, 0, "int") + , NumGet(rect, 12, "int") - NumGet(rect, 4, "int")] + } + ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") VarSetCapacity(bi, 40, 0) ; sizeof(bi) = 40 diff --git a/ImagePut.ahk b/ImagePut.ahk index 1e71a19a..bc64a207 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -325,11 +325,15 @@ class ImagePut { ; A "buffer" is an object with ptr and size properties. if image.HasOwnProp("ptr") && image.HasOwnProp("size") return "buffer" - + ; A "window" is an object with an hwnd property. if image.HasOwnProp("hwnd") return "window" + ; A "window2" is an array with a string that contains the window title. + if (image.Has(1) && WinExist(image[1])) + return "window2" + ; A "screenshot" is an array of 4 numbers. if (image[1] ~= "^-?\d+$" && image[2] ~= "^-?\d+$" && image[3] ~= "^-?\d+$" && image[4] ~= "^-?\d+$") return "screenshot" @@ -447,6 +451,9 @@ class ImagePut { if (type = "window") return this.from_window(image) + if (type = "window2") + return this.from_screenshot(image[1]) + if (type = "desktop") return this.from_desktop() @@ -1092,6 +1099,19 @@ class ImagePut { static from_screenshot(image) { ; Thanks tic - https://www.autohotkey.com/boards/viewtopic.php?t=6517 + if !IsObject(image) { + image := WinExist(image) + DllCall("GetWindowRect", "ptr", image, "ptr", rect := Buffer(16)) + + if DllCall("IsIconic", "ptr", image) + DllCall("ShowWindow", "ptr", image, "int", 1) + + image := [NumGet(rect, 0, "int") + , NumGet(rect, 4, "int") + , NumGet(rect, 8, "int") - NumGet(rect, 0, "int") + , NumGet(rect, 12, "int") - NumGet(rect, 4, "int")] + } + ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") bi := Buffer(40, 0) ; sizeof(bi) = 40 From d69156e0897a83324468f0e4c50da84094c32845 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 26 Mar 2023 13:48:12 -0400 Subject: [PATCH 397/492] Use WinGetClientPos instead --- ImagePut (for v1).ahk | 17 +++++++---------- ImagePut.ahk | 15 ++++++--------- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index aa9c8ebc..4047ce6b 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1100,16 +1100,13 @@ class ImagePut { ; Thanks tic - https://www.autohotkey.com/boards/viewtopic.php?t=6517 if !IsObject(image) { - image := WinExist(image) - DllCall("GetWindowRect", "ptr", image, "ptr", &rect := VarSetCapacity(rect, 16)) - - if DllCall("IsIconic", "ptr", image) - DllCall("ShowWindow", "ptr", image, "int", 4) - - image := [NumGet(rect, 0, "int") - , NumGet(rect, 4, "int") - , NumGet(rect, 8, "int") - NumGet(rect, 0, "int") - , NumGet(rect, 12, "int") - NumGet(rect, 4, "int")] + dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") + hwnd := WinExist(image) + VarSetCapacity(size, 16, 0) + DllCall("GetClientRect", "ptr", hwnd, "ptr", &size) + DllCall("ClientToScreen", "ptr", hwnd, "ptr", &size) + DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") + image := [NumGet(size, 0, "int"), NumGet(size, 4, "int"), NumGet(size, 8, "int"), NumGet(size, 12, "int")] } ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader diff --git a/ImagePut.ahk b/ImagePut.ahk index bc64a207..e2c5671a 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1100,17 +1100,14 @@ class ImagePut { ; Thanks tic - https://www.autohotkey.com/boards/viewtopic.php?t=6517 if !IsObject(image) { - image := WinExist(image) - DllCall("GetWindowRect", "ptr", image, "ptr", rect := Buffer(16)) + dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") + WinGetClientPos &x, &y, &w, &h, image + DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") + image := [x, y, w, h] + } - if DllCall("IsIconic", "ptr", image) - DllCall("ShowWindow", "ptr", image, "int", 1) - image := [NumGet(rect, 0, "int") - , NumGet(rect, 4, "int") - , NumGet(rect, 8, "int") - NumGet(rect, 0, "int") - , NumGet(rect, 12, "int") - NumGet(rect, 4, "int")] - } + ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") From 88a41a46b03eab1954c645b41a3ef8ca2d9ffa85 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 26 Mar 2023 13:55:50 -0400 Subject: [PATCH 398/492] use rect instead of size --- ImagePut (for v1).ahk | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 4047ce6b..c65307ea 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1102,11 +1102,11 @@ class ImagePut { if !IsObject(image) { dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") hwnd := WinExist(image) - VarSetCapacity(size, 16, 0) - DllCall("GetClientRect", "ptr", hwnd, "ptr", &size) - DllCall("ClientToScreen", "ptr", hwnd, "ptr", &size) + VarSetCapacity(rect, 16, 0) + DllCall("GetClientRect", "ptr", hwnd, "ptr", &rect) + DllCall("ClientToScreen", "ptr", hwnd, "ptr", &rect) DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") - image := [NumGet(size, 0, "int"), NumGet(size, 4, "int"), NumGet(size, 8, "int"), NumGet(size, 12, "int")] + image := [NumGet(rect, 0, "int"), NumGet(rect, 4, "int"), NumGet(rect, 8, "int"), NumGet(rect, 12, "int")] } ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader From 172d1b7e30dfcbc208f5dba44ec302678ecbed37 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 26 Mar 2023 14:00:40 -0400 Subject: [PATCH 399/492] Throw Error if IsObject branch is exited --- ImagePut (for v1).ahk | 2 ++ ImagePut.ahk | 2 ++ 2 files changed, 4 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index c65307ea..5e52fb11 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -337,6 +337,8 @@ class ImagePut { ; A "screenshot" is an array of 4 numbers. if (image[1] ~= "^-?\d+$" && image[2] ~= "^-?\d+$" && image[3] ~= "^-?\d+$" && image[4] ~= "^-?\d+$") return "screenshot" + + throw Exception("Image type could not be identified.") } SysGet MonitorGetCount, MonitorCount ; A non-zero "monitor" number identifies each display uniquely; and 0 refers to the entire virtual screen. if (image ~= "^\d+$" && image >= 0 && image <= MonitorGetCount) diff --git a/ImagePut.ahk b/ImagePut.ahk index e2c5671a..15acf124 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -337,6 +337,8 @@ class ImagePut { ; A "screenshot" is an array of 4 numbers. if (image[1] ~= "^-?\d+$" && image[2] ~= "^-?\d+$" && image[3] ~= "^-?\d+$" && image[4] ~= "^-?\d+$") return "screenshot" + + throw Error("Image type could not be identified.") } ; A non-zero "monitor" number identifies each display uniquely; and 0 refers to the entire virtual screen. if (image ~= "^\d+$" && image >= 0 && image <= MonitorGetCount()) From f36363a096fb1fc6da3b029620b39364ea110416 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 13 Apr 2023 01:24:24 -0400 Subject: [PATCH 400/492] [v2] Change "uint" to hresult. Remove +0 from v1 --- ImagePut.ahk | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index 15acf124..21bafa26 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1827,7 +1827,7 @@ class ImagePut { } ; Sample the top-left pixel and set all matching pixels to be transparent. - DllCall(code, "ptr", Scan0, "ptr", Scan0 + 4*width*height, "uint", NumGet(Scan0+0, "uint"), "cdecl") + DllCall(code, "ptr", Scan0, "ptr", Scan0 + 4*width*height, "uint", NumGet(Scan0, "uint"), "cdecl") ; Write pixels to bitmap. DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", BitmapData) @@ -1923,13 +1923,13 @@ class ImagePut { ; Requires a valid window handle via OpenClipboard or the next call to OpenClipboard will crash. DllCall("EmptyClipboard") - DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "int", False, "ptr*", &pSharedStream:=0, "uint") - DllCall("shlwapi\IStream_Size", "ptr", pStream, "uint64*", &size:=0, "uint") - DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") - DllCall("shlwapi\IStream_Copy", "ptr", pStream, "ptr", pSharedStream, "uint", size, "uint") - DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint") + DllCall("ole32\CreateStreamOnHGlobal", "ptr", 0, "int", False, "ptr*", &pSharedStream:=0, "hresult") + DllCall("shlwapi\IStream_Size", "ptr", pStream, "uint64*", &size:=0, "hresult") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "hresult") + DllCall("shlwapi\IStream_Copy", "ptr", pStream, "ptr", pSharedStream, "uint", size, "hresult") + DllCall("shlwapi\IStream_Reset", "ptr", pStream, "hresult") - DllCall("ole32\GetHGlobalFromStream", "ptr", pSharedStream, "uint*", &hData:=0, "uint") + DllCall("ole32\GetHGlobalFromStream", "ptr", pSharedStream, "uint*", &hData:=0, "hresult") ObjRelease(pSharedStream) DllCall("SetClipboardData", "uint", DllCall("RegisterClipboardFormat", "str", extension, "uint"), "ptr", hData) DllCall("CloseClipboard") From 2b70a5a9e987426f31978ca13ce9707f8e93ae9f Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 27 Apr 2023 12:21:01 -0400 Subject: [PATCH 401/492] Catch divide by zero error inside BitmapCrop (negative w&h) --- ImagePut (for v1).ahk | 8 ++++---- ImagePut.ahk | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 5e52fb11..d9d5a2e3 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -712,10 +712,10 @@ class ImagePut { safe_h := Round(crop[2] + crop[4]) - Round(crop[2]) ; Minimum size is 1 x 1. Ensure that coordinates can never exceed the expected Bitmap area. - safe_x := (safe_x >= width) ? 0 : safe_x ; Default x is zero. - safe_y := (safe_y >= height) ? 0 : safe_y ; Default y is zero. - safe_w := (safe_w = 0 || safe_x + safe_w > width) ? width - safe_x : safe_w ; Default w is max width. - safe_h := (safe_h = 0 || safe_y + safe_h > height) ? height - safe_y : safe_h ; Default h is max height. + safe_x := (safe_x >= width) ? 0 : safe_x ; Default x is zero. + safe_y := (safe_y >= height) ? 0 : safe_y ; Default y is zero. + safe_w := (safe_w <= 0 || safe_x + safe_w > width) ? width - safe_x : safe_w ; Default w is max width. + safe_h := (safe_h <= 0 || safe_y + safe_h > height) ? height - safe_y : safe_h ; Default h is max height. ; Avoid cropping if no changes are detected. if (safe_x = 0 && safe_y = 0 && safe_w = width && safe_h = height) diff --git a/ImagePut.ahk b/ImagePut.ahk index 21bafa26..ac8a65f8 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -712,10 +712,10 @@ class ImagePut { safe_h := Round(crop[2] + crop[4]) - Round(crop[2]) ; Minimum size is 1 x 1. Ensure that coordinates can never exceed the expected Bitmap area. - safe_x := (safe_x >= width) ? 0 : safe_x ; Default x is zero. - safe_y := (safe_y >= height) ? 0 : safe_y ; Default y is zero. - safe_w := (safe_w = 0 || safe_x + safe_w > width) ? width - safe_x : safe_w ; Default w is max width. - safe_h := (safe_h = 0 || safe_y + safe_h > height) ? height - safe_y : safe_h ; Default h is max height. + safe_x := (safe_x >= width) ? 0 : safe_x ; Default x is zero. + safe_y := (safe_y >= height) ? 0 : safe_y ; Default y is zero. + safe_w := (safe_w <= 0 || safe_x + safe_w > width) ? width - safe_x : safe_w ; Default w is max width. + safe_h := (safe_h <= 0 || safe_y + safe_h > height) ? height - safe_y : safe_h ; Default h is max height. ; Avoid cropping if no changes are detected. if (safe_x = 0 && safe_y = 0 && safe_w = width && safe_h = height) From 4b89b0b05e1197038d2c0a2be3c879010358d71f Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 27 Apr 2023 12:46:02 -0400 Subject: [PATCH 402/492] Apply Cropping if and only if all dimensions are valid --- ImagePut (for v1).ahk | 32 ++++++++++++++++++-------------- ImagePut.ahk | 32 ++++++++++++++++++-------------- 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index d9d5a2e3..9feff721 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -706,27 +706,31 @@ class ImagePut { crop[4] := (crop[4] < 0) ? height - Abs(crop[4]) - Abs(crop[2]) : crop[4] ; Round to the nearest integer. Reminder: width and height are distances, not coordinates. - safe_x := Round(crop[1]) - safe_y := Round(crop[2]) - safe_w := Round(crop[1] + crop[3]) - Round(crop[1]) - safe_h := Round(crop[2] + crop[4]) - Round(crop[2]) + crop[1] := Round(crop[1]) + crop[2] := Round(crop[2]) + crop[3] := Round(crop[1] + crop[3]) - Round(crop[1]) + crop[4] := Round(crop[2] + crop[4]) - Round(crop[2]) + + ; Avoid cropping if no changes are detected. + if (crop[1] = 0 && crop[2] = 0 && crop[3] == width && crop[4] == height) + return pBitmap ; Minimum size is 1 x 1. Ensure that coordinates can never exceed the expected Bitmap area. - safe_x := (safe_x >= width) ? 0 : safe_x ; Default x is zero. - safe_y := (safe_y >= height) ? 0 : safe_y ; Default y is zero. - safe_w := (safe_w <= 0 || safe_x + safe_w > width) ? width - safe_x : safe_w ; Default w is max width. - safe_h := (safe_h <= 0 || safe_y + safe_h > height) ? height - safe_y : safe_h ; Default h is max height. + safe_x := (crop[1] >= width) + safe_y := (crop[2] >= height) + safe_w := (crop[3] <= 0 || crop[1] + crop[3] > width) + safe_h := (crop[4] <= 0 || crop[2] + crop[4] > height) - ; Avoid cropping if no changes are detected. - if (safe_x = 0 && safe_y = 0 && safe_w = width && safe_h = height) + ; Abort cropping if any of the changes would exceed a safe bound. + if (safe_x || safe_y || safe_w || safe_h) return pBitmap ; Clone DllCall("gdiplus\GdipCloneBitmapAreaI" - , "int", safe_x - , "int", safe_y - , "int", safe_w - , "int", safe_h + , "int", crop[1] + , "int", crop[2] + , "int", crop[3] + , "int", crop[4] , "int", format , "ptr", pBitmap , "ptr*", pBitmapCrop:=0) diff --git a/ImagePut.ahk b/ImagePut.ahk index ac8a65f8..5f1afe6c 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -706,27 +706,31 @@ class ImagePut { crop[4] := (crop[4] < 0) ? height - Abs(crop[4]) - Abs(crop[2]) : crop[4] ; Round to the nearest integer. Reminder: width and height are distances, not coordinates. - safe_x := Round(crop[1]) - safe_y := Round(crop[2]) - safe_w := Round(crop[1] + crop[3]) - Round(crop[1]) - safe_h := Round(crop[2] + crop[4]) - Round(crop[2]) + crop[1] := Round(crop[1]) + crop[2] := Round(crop[2]) + crop[3] := Round(crop[1] + crop[3]) - Round(crop[1]) + crop[4] := Round(crop[2] + crop[4]) - Round(crop[2]) + + ; Avoid cropping if no changes are detected. + if (crop[1] = 0 && crop[2] = 0 && crop[3] == width && crop[4] == height) + return pBitmap ; Minimum size is 1 x 1. Ensure that coordinates can never exceed the expected Bitmap area. - safe_x := (safe_x >= width) ? 0 : safe_x ; Default x is zero. - safe_y := (safe_y >= height) ? 0 : safe_y ; Default y is zero. - safe_w := (safe_w <= 0 || safe_x + safe_w > width) ? width - safe_x : safe_w ; Default w is max width. - safe_h := (safe_h <= 0 || safe_y + safe_h > height) ? height - safe_y : safe_h ; Default h is max height. + safe_x := (crop[1] >= width) + safe_y := (crop[2] >= height) + safe_w := (crop[3] <= 0 || crop[1] + crop[3] > width) + safe_h := (crop[4] <= 0 || crop[2] + crop[4] > height) - ; Avoid cropping if no changes are detected. - if (safe_x = 0 && safe_y = 0 && safe_w = width && safe_h = height) + ; Abort cropping if any of the changes would exceed a safe bound. + if (safe_x || safe_y || safe_w || safe_h) return pBitmap ; Clone DllCall("gdiplus\GdipCloneBitmapAreaI" - , "int", safe_x - , "int", safe_y - , "int", safe_w - , "int", safe_h + , "int", crop[1] + , "int", crop[2] + , "int", crop[3] + , "int", crop[4] , "int", format , "ptr", pBitmap , "ptr*", &pBitmapCrop:=0) From d1358af59f7cfdbd765b28b4a03bad595644ee35 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 27 Apr 2023 13:08:52 -0400 Subject: [PATCH 403/492] Add upscale && downscale flags --- ImagePut (for v1).ahk | 16 +++++++++++++--- ImagePut.ahk | 16 +++++++++++++--- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 9feff721..f815f40e 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -186,12 +186,12 @@ class ImagePut { type := this.ImageType(image) crop := keywords.crop - scale := keywords.scale + scale := keywords.scale, upscale := keywords.upscale, downscale := keywords.downscale decode := (keywords.decode != "") ? keywords.decode : this.decode validate := (keywords.validate != "") ? keywords.validate : this.validate ; #1 - Stream intermediate. - if not decode and not crop and not scale + if not decode and not crop and not (scale || upscale || downscale) and (type ~= "^(?i:clipboard_png|pdf|url|file|stream|RandomAccessStream|hex|base64)$") and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64|uri|explorer|safeArray|formData)$") and (p[1] == "") { ; For now, disallow any specification of extensions. @@ -221,6 +221,8 @@ class ImagePut { (validate) && DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmap) (crop) && this.BitmapCrop(pBitmap, crop) (scale) && this.BitmapScale(pBitmap, scale) + (upscale) && this.BitmapScale(pBitmap, upscale, 1) + (downscale) && this.BitmapScale(pBitmap, downscale, -1) coimage := this.BitmapToCoimage(cotype, pBitmap, p*) ; Clean up the pBitmap copy. Export raw pointers if requested. @@ -740,7 +742,7 @@ class ImagePut { return pBitmap := pBitmapCrop } - BitmapScale(ByRef pBitmap, scale) { + BitmapScale(ByRef pBitmap, scale, direction := 0) { if not (IsObject(scale) && ((scale[1] ~= "^\d+$") || (scale[2] ~= "^\d+$")) || (scale ~= "^\d+(\.\d+)?$")) throw Exception("Invalid scale.") @@ -761,6 +763,14 @@ class ImagePut { if (safe_w = width && safe_h = height) return pBitmap + ; Force upscaling. + if (direction > 0 and (safe_w < width && safe_h < height)) + return pBitmap + + ; Force downscaling. + if (direction < 0 and (safe_w > width && safe_h > height)) + return pBitmap + ; Create a new bitmap and get the graphics context. DllCall("gdiplus\GdipCreateBitmapFromScan0" , "int", safe_w, "int", safe_h, "int", 0, "int", format, "ptr", 0, "ptr*", pBitmapScale:=0) diff --git a/ImagePut.ahk b/ImagePut.ahk index 5f1afe6c..1dbd5d14 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -186,12 +186,12 @@ class ImagePut { type := this.ImageType(image) crop := keywords.crop - scale := keywords.scale + scale := keywords.scale, upscale := keywords.upscale, downscale := keywords.downscale decode := (keywords.decode != "") ? keywords.decode : this.decode validate := (keywords.validate != "") ? keywords.validate : this.validate ; #1 - Stream intermediate. - if not decode and not crop and not scale + if not decode and not crop and not (scale || upscale || downscale) and (type ~= "^(?i:clipboard_png|pdf|url|file|stream|RandomAccessStream|hex|base64)$") and (cotype ~= "^(?i:file|stream|RandomAccessStream|hex|base64|uri|explorer|safeArray|formData)$") and (!p.Has(1) || p[1] == "") { ; For now, disallow any specification of extensions. @@ -221,6 +221,8 @@ class ImagePut { (validate) && DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmap) (crop) && this.BitmapCrop(&pBitmap, crop) (scale) && this.BitmapScale(&pBitmap, scale) + (upscale) && this.BitmapScale(&pBitmap, upscale, 1) + (downscale) && this.BitmapScale(&pBitmap, downscale, -1) coimage := this.BitmapToCoimage(cotype, pBitmap, p*) ; Clean up the pBitmap copy. Export raw pointers if requested. @@ -740,7 +742,7 @@ class ImagePut { return pBitmap := pBitmapCrop } - static BitmapScale(&pBitmap, scale) { + static BitmapScale(&pBitmap, scale, direction := 0) { if not (IsObject(scale) && ((scale[1] ~= "^\d+$") || (scale[2] ~= "^\d+$")) || (scale ~= "^\d+(\.\d+)?$")) throw Error("Invalid scale.") @@ -761,6 +763,14 @@ class ImagePut { if (safe_w = width && safe_h = height) return pBitmap + ; Force upscaling. + if (direction > 0 and (safe_w < width && safe_h < height)) + return pBitmap + + ; Force downscaling. + if (direction < 0 and (safe_w > width && safe_h > height)) + return pBitmap + ; Create a new bitmap and get the graphics context. DllCall("gdiplus\GdipCreateBitmapFromScan0" , "int", safe_w, "int", safe_h, "int", 0, "int", format, "ptr", 0, "ptr*", &pBitmapScale:=0) From 13733a959712706b7cb41fd19f4ee3b7ced580e7 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 27 Apr 2023 16:22:58 -0400 Subject: [PATCH 404/492] Fix SetThreadDpiAwarenessContext for Windows 7 --- ImagePut (for v1).ahk | 36 ++++++++++++++++++------------------ ImagePut.ahk | 40 ++++++++++++++++++++-------------------- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index f815f40e..00845a89 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1116,12 +1116,12 @@ class ImagePut { ; Thanks tic - https://www.autohotkey.com/boards/viewtopic.php?t=6517 if !IsObject(image) { - dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") + try dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") hwnd := WinExist(image) VarSetCapacity(rect, 16, 0) DllCall("GetClientRect", "ptr", hwnd, "ptr", &rect) DllCall("ClientToScreen", "ptr", hwnd, "ptr", &rect) - DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") + try DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") image := [NumGet(rect, 0, "int"), NumGet(rect, 4, "int"), NumGet(rect, 8, "int"), NumGet(rect, 12, "int")] } @@ -1178,11 +1178,11 @@ class ImagePut { } ; Get the width and height of the client window. - dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", DPI_AWARENESS ? -3 : -5, "ptr") + try dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", DPI_AWARENESS ? -3 : -5, "ptr") DllCall("GetClientRect", "ptr", image, "ptr", &Rect := VarSetCapacity(Rect, 16)) ; sizeof(RECT) = 16 , width := NumGet(Rect, 8, "int") , height := NumGet(Rect, 12, "int") - DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") + try DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") @@ -1225,11 +1225,11 @@ class ImagePut { throw Exception("Could not locate hidden window behind desktop.") ; Get the width and height of the client window. - dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") + try dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") DllCall("GetClientRect", "ptr", WorkerW, "ptr", &Rect := VarSetCapacity(Rect, 16)) ; sizeof(RECT) = 16 , width := NumGet(Rect, 8, "int") , height := NumGet(Rect, 12, "int") - DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") + try DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") ; Get device context of spawned window. sdc := DllCall("GetDCEx", "ptr", WorkerW, "ptr", 0, "int", 0x403, "ptr") ; LockWindowUpdate | Cache | Window @@ -1266,10 +1266,10 @@ class ImagePut { from_wallpaper() { ; Get the width and height of all monitors. - dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") + try dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") width := DllCall("GetSystemMetrics", "int", 78, "int") height := DllCall("GetSystemMetrics", "int", 79, "int") - DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") + try DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") @@ -1501,7 +1501,7 @@ class ImagePut { } from_monitor(image) { - dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") + try dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") if (image > 0) { SysGet _, Monitor, % image x := _Left @@ -1514,7 +1514,7 @@ class ImagePut { w := DllCall("GetSystemMetrics", "int", 78, "int") h := DllCall("GetSystemMetrics", "int", 79, "int") } - DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") + try DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") return this.from_screenshot([x,y,w,h]) } @@ -2548,10 +2548,10 @@ class ImagePut { DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) ; Get Screen width and height with DPI awareness. - dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") + try dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") ScreenWidth := A_ScreenWidth ScreenHeight := A_ScreenHeight - DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") + try DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") ; If both dimensions exceed the screen boundaries, compare the aspect ratio of the image ; to the aspect ratio of the screen to determine the scale factor. Default scale is 1. @@ -2581,7 +2581,7 @@ class ImagePut { DllCall("AdjustWindowRectEx", "ptr", &rect, "uint", style, "uint", 0, "uint", styleEx) - dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") + try dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") hwnd := DllCall("CreateWindowEx" , "uint", styleEx , "str", this.WindowClass() ; lpClassName @@ -2596,7 +2596,7 @@ class ImagePut { , "ptr", 0 ; hInstance , "ptr", 0 ; lpParam , "ptr") - DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") + try DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") ; Tests have shown that changing the system default colors has no effect on F0F0F0. ; Must call SetWindowLong with WS_EX_LAYERED immediately before SetLayeredWindowAttributes. @@ -2638,10 +2638,10 @@ class ImagePut { DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) ; Get Screen width and height with DPI awareness. - dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") + try dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") ScreenWidth := A_ScreenWidth ScreenHeight := A_ScreenHeight - DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") + try DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") ; If both dimensions exceed the screen boundaries, compare the aspect ratio of the image ; to the aspect ratio of the screen to determine the scale factor. Default scale is 1. @@ -2721,7 +2721,7 @@ class ImagePut { DllCall("gdiplus\GdipDeleteGraphics", "ptr", pGraphics) } - dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") + try dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") hwnd := DllCall("CreateWindowEx" , "uint", styleEx | WS_EX_LAYERED ; dwExStyle , "str", this.WindowClass() ; lpClassName @@ -2736,7 +2736,7 @@ class ImagePut { , "ptr", 0 ; hInstance , "ptr", 0 ; lpParam , "ptr") - DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") + try DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") ; Draw the contents of the device context onto the layered window. DllCall("UpdateLayeredWindow" diff --git a/ImagePut.ahk b/ImagePut.ahk index 1dbd5d14..0ef70cb2 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1065,12 +1065,12 @@ class ImagePut { } ; Get true virtual screen coordinates. - dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") + try dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") x := DllCall("GetSystemMetrics", "int", 76, "int") y := DllCall("GetSystemMetrics", "int", 77, "int") width := DllCall("GetSystemMetrics", "int", 78, "int") height := DllCall("GetSystemMetrics", "int", 79, "int") - DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") + try DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") return {x:x, y:y, width: width, height: height, @@ -1116,9 +1116,9 @@ class ImagePut { ; Thanks tic - https://www.autohotkey.com/boards/viewtopic.php?t=6517 if !IsObject(image) { - dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") + try dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") WinGetClientPos &x, &y, &w, &h, image - DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") + try DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") image := [x, y, w, h] } @@ -1178,11 +1178,11 @@ class ImagePut { } ; Get the width and height of the client window. - dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", DPI_AWARENESS ? -3 : -5, "ptr") + try dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", DPI_AWARENESS ? -3 : -5, "ptr") DllCall("GetClientRect", "ptr", image, "ptr", Rect := Buffer(16)) ; sizeof(RECT) = 16 , width := NumGet(Rect, 8, "int") , height := NumGet(Rect, 12, "int") - DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") + try DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") @@ -1225,11 +1225,11 @@ class ImagePut { throw Error("Could not locate hidden window behind desktop.") ; Get the width and height of the client window. - dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") + try dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") DllCall("GetClientRect", "ptr", WorkerW, "ptr", Rect := Buffer(16)) ; sizeof(RECT) = 16 , width := NumGet(Rect, 8, "int") , height := NumGet(Rect, 12, "int") - DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") + try DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") ; Get device context of spawned window. sdc := DllCall("GetDCEx", "ptr", WorkerW, "ptr", 0, "int", 0x403, "ptr") ; LockWindowUpdate | Cache | Window @@ -1266,10 +1266,10 @@ class ImagePut { static from_wallpaper() { ; Get the width and height of all monitors. - dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") + try dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") width := DllCall("GetSystemMetrics", "int", 78, "int") height := DllCall("GetSystemMetrics", "int", 79, "int") - DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") + try DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") @@ -1501,7 +1501,7 @@ class ImagePut { } static from_monitor(image) { - dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") + try dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") if (image > 0) { MonitorGet(image, &Left, &Top, &Right, &Bottom) x := Left @@ -1514,7 +1514,7 @@ class ImagePut { w := DllCall("GetSystemMetrics", "int", 78, "int") h := DllCall("GetSystemMetrics", "int", 79, "int") } - DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") + try DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") return this.from_screenshot([x,y,w,h]) } @@ -2548,10 +2548,10 @@ class ImagePut { DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) ; Get Screen width and height with DPI awareness. - dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") + try dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") ScreenWidth := A_ScreenWidth ScreenHeight := A_ScreenHeight - DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") + try DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") ; If both dimensions exceed the screen boundaries, compare the aspect ratio of the image ; to the aspect ratio of the screen to determine the scale factor. Default scale is 1. @@ -2581,7 +2581,7 @@ class ImagePut { DllCall("AdjustWindowRectEx", "ptr", rect, "uint", style, "uint", 0, "uint", styleEx) - dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") + try dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") hwnd := DllCall("CreateWindowEx" , "uint", styleEx , "str", this.WindowClass() ; lpClassName @@ -2596,7 +2596,7 @@ class ImagePut { , "ptr", 0 ; hInstance , "ptr", 0 ; lpParam , "ptr") - DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") + try DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") ; Tests have shown that changing the system default colors has no effect on F0F0F0. ; Must call SetWindowLong with WS_EX_LAYERED immediately before SetLayeredWindowAttributes. @@ -2638,10 +2638,10 @@ class ImagePut { DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) ; Get Screen width and height with DPI awareness. - dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") + try dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") ScreenWidth := A_ScreenWidth ScreenHeight := A_ScreenHeight - DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") + try DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") ; If both dimensions exceed the screen boundaries, compare the aspect ratio of the image ; to the aspect ratio of the screen to determine the scale factor. Default scale is 1. @@ -2721,7 +2721,7 @@ class ImagePut { DllCall("gdiplus\GdipDeleteGraphics", "ptr", pGraphics) } - dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") + try dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") hwnd := DllCall("CreateWindowEx" , "uint", styleEx | WS_EX_LAYERED ; dwExStyle , "str", this.WindowClass() ; lpClassName @@ -2736,7 +2736,7 @@ class ImagePut { , "ptr", 0 ; hInstance , "ptr", 0 ; lpParam , "ptr") - DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") + try DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") ; Draw the contents of the device context onto the layered window. DllCall("UpdateLayeredWindow" From 91e541d85f7793bfdb5e235136a49307c56c113e Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 27 Apr 2023 16:34:36 -0400 Subject: [PATCH 405/492] Remove window2 a.k.a. screenshot with ["A"] --- ImagePut (for v1).ahk | 7 ------- ImagePut.ahk | 7 ------- 2 files changed, 14 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 00845a89..52adeee2 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -332,10 +332,6 @@ class ImagePut { if image.HasKey("hwnd") return "window" - ; A "window2" is an array with a string that contains the window title. - if (image.HasKey(1) && WinExist(image[1])) - return "window2" - ; A "screenshot" is an array of 4 numbers. if (image[1] ~= "^-?\d+$" && image[2] ~= "^-?\d+$" && image[3] ~= "^-?\d+$" && image[4] ~= "^-?\d+$") return "screenshot" @@ -455,9 +451,6 @@ class ImagePut { if (type = "window") return this.from_window(image) - if (type = "window2") - return this.from_screenshot(image[1]) - if (type = "desktop") return this.from_desktop() diff --git a/ImagePut.ahk b/ImagePut.ahk index 0ef70cb2..4a295de1 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -332,10 +332,6 @@ class ImagePut { if image.HasOwnProp("hwnd") return "window" - ; A "window2" is an array with a string that contains the window title. - if (image.Has(1) && WinExist(image[1])) - return "window2" - ; A "screenshot" is an array of 4 numbers. if (image[1] ~= "^-?\d+$" && image[2] ~= "^-?\d+$" && image[3] ~= "^-?\d+$" && image[4] ~= "^-?\d+$") return "screenshot" @@ -455,9 +451,6 @@ class ImagePut { if (type = "window") return this.from_window(image) - if (type = "window2") - return this.from_screenshot(image[1]) - if (type = "desktop") return this.from_desktop() From 0b193f9fade94e5402778ee0f200cd49fb45a8c5 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 27 Apr 2023 22:49:55 -0400 Subject: [PATCH 406/492] removed annoying __32 for SetWindowLongPtr --- ImagePut (for v1).ahk | 37 +++++++++++++++++-------------------- ImagePut.ahk | 37 +++++++++++++++++-------------------- 2 files changed, 34 insertions(+), 40 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 52adeee2..e27d3294 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2597,14 +2597,13 @@ class ImagePut { DllCall("SetLayeredWindowAttributes", "ptr", hwnd, "uint", 0xF0F0F0, "uchar", 0, "int", 1) ; Set itself as the *internal* top level window. - __32 := A_PtrSize = 8 ? "Ptr" : "" ; Fixes 32-bit windows - DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 0, "ptr", hwnd) + DllCall("SetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 0, "ptr", hwnd) ; A layered child window is only available on Windows 8+. hwnd_child := this.show(pBitmap, title, [0, 0, w, h], WS_CHILD | WS_VISIBLE, WS_EX_LAYERED, hwnd) ; Override the child's internal hwnd with the parent's hwnd. - DllCall("SetWindowLong" __32, "ptr", hwnd_child, "int", 0, "ptr", hwnd) + DllCall("SetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd_child, "int", 0, "ptr", hwnd) ; Prevent empty windows from showing. DllCall("ShowWindow", "ptr", hwnd, "int", 1) @@ -2744,8 +2743,7 @@ class ImagePut { , "uint", 2) ; dwFlags ; Set itself as the *internal* top level window. - __32 := A_PtrSize = 8 ? "Ptr" : "" ; Fixes 32-bit windows - DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 0, "ptr", hwnd) + DllCall("SetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 0, "ptr", hwnd) ; Check for multiple frames. DllCall("gdiplus\GdipImageGetFrameDimensionsCount", "ptr", pBitmap, "uint*", dims:=0) @@ -2764,10 +2762,10 @@ class ImagePut { DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmapClone) ; Store data inside window class extra bits (cbWndExtra). - DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 1*A_PtrSize, "ptr", pBitmapClone) - DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 2*A_PtrSize, "ptr", hdc) - DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 3*A_PtrSize, "ptr", Item) - DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 4*A_PtrSize, "ptr", pBits) + DllCall("SetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 1*A_PtrSize, "ptr", pBitmapClone) + DllCall("SetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 2*A_PtrSize, "ptr", hdc) + DllCall("SetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 3*A_PtrSize, "ptr", Item) + DllCall("SetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 4*A_PtrSize, "ptr", pBits) ; Preserve GDI+ scope. ImagePut.gdiplusStartup() @@ -2826,7 +2824,6 @@ class ImagePut { } ; Define window behavior. WindowProc(uMsg, wParam, lParam) { - __32 := A_PtrSize = 8 ? "Ptr" : "" ; Fixes 32-bit windows hwnd := this ; Prevent the script from exiting early. static void := ObjBindMethod({}, {}) @@ -2837,12 +2834,12 @@ class ImagePut { ; WM_DESTROY if (uMsg = 0x2) { - if pBitmap := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 1*A_PtrSize, "ptr") { - hdc := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 2*A_PtrSize, "ptr") - Item := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 3*A_PtrSize, "ptr") + if pBitmap := DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 1*A_PtrSize, "ptr") { + hdc := DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 2*A_PtrSize, "ptr") + Item := DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 3*A_PtrSize, "ptr") ; Exit loop. - DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 1*A_PtrSize, "ptr", 0) + DllCall("SetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 1*A_PtrSize, "ptr", 0) ; Dispose of all data stored in the window class. DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) @@ -2860,13 +2857,13 @@ class ImagePut { ; WM_LBUTTONDOWN if (uMsg = 0x201) { - hwnd := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 0, "ptr") ; internal parent hwnd + hwnd := DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 0, "ptr") ; internal parent hwnd return DllCall("DefWindowProc", "ptr", hwnd, "uint", 0xA1, "uptr", 2, "ptr", 0, "ptr") } ; WM_RBUTTONUP if (uMsg = 0x205) { - hwnd := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 0, "ptr") ; internal parent hwnd + hwnd := DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 0, "ptr") ; internal parent hwnd DllCall("DestroyWindow", "ptr", hwnd) return 0 } @@ -2877,10 +2874,10 @@ class ImagePut { Critical ; Get variables. - pBitmap := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 1*A_PtrSize, "ptr") - hdc := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 2*A_PtrSize, "ptr") - Item := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 3*A_PtrSize, "ptr") - pBits := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 4*A_PtrSize, "ptr") + pBitmap := DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 1*A_PtrSize, "ptr") + hdc := DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 2*A_PtrSize, "ptr") + Item := DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 3*A_PtrSize, "ptr") + pBits := DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 4*A_PtrSize, "ptr") ; Exit loop. if !pBitmap diff --git a/ImagePut.ahk b/ImagePut.ahk index 4a295de1..51e8de60 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2597,14 +2597,13 @@ class ImagePut { DllCall("SetLayeredWindowAttributes", "ptr", hwnd, "uint", 0xF0F0F0, "uchar", 0, "int", 1) ; Set itself as the *internal* top level window. - __32 := A_PtrSize = 8 ? "Ptr" : "" ; Fixes 32-bit windows - DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 0, "ptr", hwnd) + DllCall("SetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 0, "ptr", hwnd) ; A layered child window is only available on Windows 8+. hwnd_child := this.show(pBitmap, title, [0, 0, w, h], WS_CHILD | WS_VISIBLE, WS_EX_LAYERED, hwnd) ; Override the child's internal hwnd with the parent's hwnd. - DllCall("SetWindowLong" __32, "ptr", hwnd_child, "int", 0, "ptr", hwnd) + DllCall("SetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd_child, "int", 0, "ptr", hwnd) ; Prevent empty windows from showing. DllCall("ShowWindow", "ptr", hwnd, "int", 1) @@ -2744,8 +2743,7 @@ class ImagePut { , "uint", 2) ; dwFlags ; Set itself as the *internal* top level window. - __32 := A_PtrSize = 8 ? "Ptr" : "" ; Fixes 32-bit windows - DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 0, "ptr", hwnd) + DllCall("SetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 0, "ptr", hwnd) ; Check for multiple frames. DllCall("gdiplus\GdipImageGetFrameDimensionsCount", "ptr", pBitmap, "uint*", &dims:=0) @@ -2764,10 +2762,10 @@ class ImagePut { DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmapClone) ; Store data inside window class extra bits (cbWndExtra). - DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 1*A_PtrSize, "ptr", pBitmapClone) - DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 2*A_PtrSize, "ptr", hdc) - DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 3*A_PtrSize, "ptr", Item) - DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 4*A_PtrSize, "ptr", pBits) + DllCall("SetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 1*A_PtrSize, "ptr", pBitmapClone) + DllCall("SetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 2*A_PtrSize, "ptr", hdc) + DllCall("SetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 3*A_PtrSize, "ptr", Item) + DllCall("SetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 4*A_PtrSize, "ptr", pBits) ; Preserve GDI+ scope. ImagePut.gdiplusStartup() @@ -2826,7 +2824,6 @@ class ImagePut { ; Define window behavior. WindowProc(hwnd, uMsg, wParam, lParam) { - __32 := A_PtrSize = 8 ? "Ptr" : "" ; Fixes 32-bit windows ; Prevent the script from exiting early. static active_windows := Persistent() @@ -2837,12 +2834,12 @@ class ImagePut { ; WM_DESTROY if (uMsg = 0x2) { - if pBitmap := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 1*A_PtrSize, "ptr") { - hdc := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 2*A_PtrSize, "ptr") - Item := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 3*A_PtrSize, "ptr") + if pBitmap := DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 1*A_PtrSize, "ptr") { + hdc := DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 2*A_PtrSize, "ptr") + Item := DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 3*A_PtrSize, "ptr") ; Exit loop. - DllCall("SetWindowLong" __32, "ptr", hwnd, "int", 1*A_PtrSize, "ptr", 0) + DllCall("SetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 1*A_PtrSize, "ptr", 0) ; Dispose of all data stored in the window class. DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) @@ -2860,13 +2857,13 @@ class ImagePut { ; WM_LBUTTONDOWN if (uMsg = 0x201) { - hwnd := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 0, "ptr") ; internal parent hwnd + hwnd := DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 0, "ptr") ; internal parent hwnd return DllCall("DefWindowProc", "ptr", hwnd, "uint", 0xA1, "uptr", 2, "ptr", 0, "ptr") } ; WM_RBUTTONUP if (uMsg = 0x205) { - hwnd := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 0, "ptr") ; internal parent hwnd + hwnd := DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 0, "ptr") ; internal parent hwnd DllCall("DestroyWindow", "ptr", hwnd) return 0 } @@ -2877,10 +2874,10 @@ class ImagePut { Critical ; Get variables. - pBitmap := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 1*A_PtrSize, "ptr") - hdc := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 2*A_PtrSize, "ptr") - Item := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 3*A_PtrSize, "ptr") - pBits := DllCall("GetWindowLong" __32, "ptr", hwnd, "int", 4*A_PtrSize, "ptr") + pBitmap := DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 1*A_PtrSize, "ptr") + hdc := DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 2*A_PtrSize, "ptr") + Item := DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 3*A_PtrSize, "ptr") + pBits := DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 4*A_PtrSize, "ptr") ; Exit loop. if !pBitmap From b93901537e0986a930b36b9fd3117217ac09ebbb Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 29 Apr 2023 21:02:30 -0400 Subject: [PATCH 407/492] read / write from shared buffers --- ImagePut (for v1).ahk | 57 +++++++++++++++++++++++++++++++++++++++++++ ImagePut.ahk | 57 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index e27d3294..2c9a3deb 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1975,6 +1975,63 @@ class ImagePut { return new ImagePut.BitmapBuffer(ptr, size, width, height, free) } + read_sharedbuffer(image) { + hMap := DllCall("OpenFileMapping", "uint", 0x2, "int", 0, "str", image, "ptr") + pMap := DllCall("MapViewOfFile", "ptr", hMap, "uint", 0x2, "uint", 0, "uint", 0, "uptr", 0, "ptr") + + width := RegExReplace(image, ".*?(\d+)x\d+", "$1") + height := RegExReplace(image, ".*?\d+x(\d+)", "$1") + size := 4 * width * height + + free := DllCall.bind("UnmapViewOfFile", "ptr", pMap) + ; DllCall("UnmapViewOfFile", "ptr", pMap), + ; DllCall("CloseHandle", "ptr", hMap) + ;) + + buf := new ImagePut.BitmapBuffer(pMap, size, width, height, free) + buf.name := image + return buf + } + + to_sharedbuffer(pBitmap) { + ; Get Bitmap width and height. + DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) + DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) + + ; Allocate shared memory. + name := "Alice" width "x" height + size := 4 * width * height + hMap := DllCall("CreateFileMapping", "ptr", -1, "ptr", 0, "uint", 0x4, "uint", 0, "uint", size, "str", name, "ptr") + pMap := DllCall("MapViewOfFile", "ptr", hMap, "uint", 0x2, "uint", 0, "uint", 0, "uptr", 0, "ptr") + + ; Create a pixel buffer. + VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 + NumPut( width, Rect, 8, "uint") ; Width + NumPut( height, Rect, 12, "uint") ; Height + VarSetCapacity(BitmapData, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + NumPut( 4 * width, BitmapData, 8, "int") ; Stride + NumPut( pMap, BitmapData, 16, "ptr") ; Scan0 + DllCall("gdiplus\GdipBitmapLockBits" + , "ptr", pBitmap + , "ptr", &Rect + , "uint", 5 ; ImageLockMode.UserInputBuffer | ImageLockMode.ReadOnly + , "int", 0x26200A ; Format32bppArgb + , "ptr", &BitmapData) + + ; Write pixels to buffer. + DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", &BitmapData) + + ; Free the pixels later. + free := DllCall.bind("UnmapViewOfFile", "ptr", pMap) + ;free := () => ( + ; DllCall("UnmapViewOfFile", "ptr", pMap), + ;) + + buf := new ImagePut.BitmapBuffer(pMap, size, width, height, free) + buf.name := name + return buf + } + class BitmapBuffer { __New(ptr, size, width, height, free:="") { diff --git a/ImagePut.ahk b/ImagePut.ahk index 51e8de60..5dc74c71 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1975,6 +1975,63 @@ class ImagePut { return ImagePut.BitmapBuffer(ptr, size, width, height, free) } + static read_sharedbuffer(image) { + hMap := DllCall("OpenFileMapping", "uint", 0x2, "int", 0, "str", image, "ptr") + pMap := DllCall("MapViewOfFile", "ptr", hMap, "uint", 0x2, "uint", 0, "uint", 0, "uptr", 0, "ptr") + + width := RegExReplace(image, ".*?(\d+)x\d+", "$1") + height := RegExReplace(image, ".*?\d+x(\d+)", "$1") + size := 4 * width * height + + free := () => ( + DllCall("UnmapViewOfFile", "ptr", pMap), + DllCall("CloseHandle", "ptr", hMap) + ) + + buf := ImagePut.BitmapBuffer(pMap, size, width, height, free) + buf.name := image + return buf + } + + static to_sharedbuffer(pBitmap) { + ; Get Bitmap width and height. + DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) + DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) + + ; Allocate shared memory. + name := "Alice" width "x" height + size := 4 * width * height + hMap := DllCall("CreateFileMapping", "ptr", -1, "ptr", 0, "uint", 0x4, "uint", 0, "uint", size, "str", name, "ptr") + pMap := DllCall("MapViewOfFile", "ptr", hMap, "uint", 0x2, "uint", 0, "uint", 0, "uptr", 0, "ptr") + + ; Target a pixel buffer. + Rect := Buffer(16, 0) ; sizeof(Rect) = 16 + NumPut( "uint", width, Rect, 8) ; Width + NumPut( "uint", height, Rect, 12) ; Height + BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 + NumPut( "int", 4 * width, BitmapData, 8) ; Stride + NumPut( "ptr", pMap, BitmapData, 16) ; Scan0 + DllCall("gdiplus\GdipBitmapLockBits" + , "ptr", pBitmap + , "ptr", Rect + , "uint", 5 ; ImageLockMode.UserInputBuffer | ImageLockMode.ReadOnly + , "int", 0x26200A ; Format32bppArgb + , "ptr", BitmapData) + + ; Write pixels to buffer. + DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", BitmapData) + + ; Free the pixels later. + free := () => ( + DllCall("UnmapViewOfFile", "ptr", pMap), + DllCall("CloseHandle", "ptr", hMap) + ) + + buf := ImagePut.BitmapBuffer(pMap, size, width, height, free) + buf.name := name + return buf + } + class BitmapBuffer { __New(ptr, size, width, height, free:="") { From 248201a00b652dea2c2dda07a45cc8d1026f9319 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 30 Apr 2023 09:23:25 -0400 Subject: [PATCH 408/492] Use first 8 bytes of FileMapping to store w&h --- ImagePut (for v1).ahk | 21 +++++++++++++-------- ImagePut.ahk | 19 ++++++++++++------- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 2c9a3deb..0c795a08 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1979,38 +1979,43 @@ class ImagePut { hMap := DllCall("OpenFileMapping", "uint", 0x2, "int", 0, "str", image, "ptr") pMap := DllCall("MapViewOfFile", "ptr", hMap, "uint", 0x2, "uint", 0, "uint", 0, "uptr", 0, "ptr") - width := RegExReplace(image, ".*?(\d+)x\d+", "$1") - height := RegExReplace(image, ".*?\d+x(\d+)", "$1") + width := NumGet(pMap + 0, "uint") + height := NumGet(pMap + 4, "uint") size := 4 * width * height + ptr := pMap + 8 free := DllCall.bind("UnmapViewOfFile", "ptr", pMap) ; DllCall("UnmapViewOfFile", "ptr", pMap), ; DllCall("CloseHandle", "ptr", hMap) ;) - buf := new ImagePut.BitmapBuffer(pMap, size, width, height, free) + buf := new ImagePut.BitmapBuffer(ptr, size, width, height, free) buf.name := image return buf } - to_sharedbuffer(pBitmap) { + to_sharedbuffer(pBitmap, name := "Alice") { ; Get Bitmap width and height. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) ; Allocate shared memory. - name := "Alice" width "x" height size := 4 * width * height hMap := DllCall("CreateFileMapping", "ptr", -1, "ptr", 0, "uint", 0x4, "uint", 0, "uint", size, "str", name, "ptr") pMap := DllCall("MapViewOfFile", "ptr", hMap, "uint", 0x2, "uint", 0, "uint", 0, "uptr", 0, "ptr") - ; Create a pixel buffer. + ; Store width and height in the first 8 bytes. + NumPut( width, pMap, 0, "uint") + NumPut(height, pMap, 4, "uint") + ptr := pMap + 8 + + ; Target a pixel buffer. VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 NumPut( width, Rect, 8, "uint") ; Width NumPut( height, Rect, 12, "uint") ; Height VarSetCapacity(BitmapData, 16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 NumPut( 4 * width, BitmapData, 8, "int") ; Stride - NumPut( pMap, BitmapData, 16, "ptr") ; Scan0 + NumPut( ptr, BitmapData, 16, "ptr") ; Scan0 DllCall("gdiplus\GdipBitmapLockBits" , "ptr", pBitmap , "ptr", &Rect @@ -2027,7 +2032,7 @@ class ImagePut { ; DllCall("UnmapViewOfFile", "ptr", pMap), ;) - buf := new ImagePut.BitmapBuffer(pMap, size, width, height, free) + buf := new ImagePut.BitmapBuffer(ptr, size, width, height, free) buf.name := name return buf } diff --git a/ImagePut.ahk b/ImagePut.ahk index 5dc74c71..ffeb51f7 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1979,38 +1979,43 @@ class ImagePut { hMap := DllCall("OpenFileMapping", "uint", 0x2, "int", 0, "str", image, "ptr") pMap := DllCall("MapViewOfFile", "ptr", hMap, "uint", 0x2, "uint", 0, "uint", 0, "uptr", 0, "ptr") - width := RegExReplace(image, ".*?(\d+)x\d+", "$1") - height := RegExReplace(image, ".*?\d+x(\d+)", "$1") + width := NumGet(pMap + 0, "uint") + height := NumGet(pMap + 4, "uint") size := 4 * width * height + ptr := pMap + 8 free := () => ( DllCall("UnmapViewOfFile", "ptr", pMap), DllCall("CloseHandle", "ptr", hMap) ) - buf := ImagePut.BitmapBuffer(pMap, size, width, height, free) + buf := ImagePut.BitmapBuffer(ptr, size, width, height, free) buf.name := image return buf } - static to_sharedbuffer(pBitmap) { + static to_sharedbuffer(pBitmap, name := "Alice") { ; Get Bitmap width and height. DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) ; Allocate shared memory. - name := "Alice" width "x" height size := 4 * width * height hMap := DllCall("CreateFileMapping", "ptr", -1, "ptr", 0, "uint", 0x4, "uint", 0, "uint", size, "str", name, "ptr") pMap := DllCall("MapViewOfFile", "ptr", hMap, "uint", 0x2, "uint", 0, "uint", 0, "uptr", 0, "ptr") + ; Store width and height in the first 8 bytes. + NumPut("uint", width, pMap, 0) + NumPut("uint", height, pMap, 4) + ptr := pMap + 8 + ; Target a pixel buffer. Rect := Buffer(16, 0) ; sizeof(Rect) = 16 NumPut( "uint", width, Rect, 8) ; Width NumPut( "uint", height, Rect, 12) ; Height BitmapData := Buffer(16+2*A_PtrSize, 0) ; sizeof(BitmapData) = 24, 32 NumPut( "int", 4 * width, BitmapData, 8) ; Stride - NumPut( "ptr", pMap, BitmapData, 16) ; Scan0 + NumPut( "ptr", ptr, BitmapData, 16) ; Scan0 DllCall("gdiplus\GdipBitmapLockBits" , "ptr", pBitmap , "ptr", Rect @@ -2027,7 +2032,7 @@ class ImagePut { DllCall("CloseHandle", "ptr", hMap) ) - buf := ImagePut.BitmapBuffer(pMap, size, width, height, free) + buf := ImagePut.BitmapBuffer(ptr, size, width, height, free) buf.name := name return buf } From 3cdc4a918b13e8d99bc006e5996bcf603b677b30 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 30 Apr 2023 09:37:49 -0400 Subject: [PATCH 409/492] Add ImagePutSharedBuffer() --- ImagePut (for v1).ahk | 10 ++++++++++ ImagePut.ahk | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 0c795a08..46b49f7b 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -105,6 +105,12 @@ ImagePutScreenshot(image, screenshot := "", alpha := "") { return ImagePut("screenshot", image, screenshot, alpha) } +; Puts the image into a file mapping and returns a buffer object sharable across processes. +; name - Global Name | string -> "Alice" +ImagePutSharedBuffer(image, name := "") { + return ImagePut("SharedBuffer", image, name) +} + ; Puts the image into a file format and returns a pointer to a stream. ; extension - File Encoding | string -> bmp, gif, jpg, png, tiff ; quality - JPEG Quality Level | integer -> 0 - 100 @@ -514,6 +520,10 @@ class ImagePut { if (cotype = "buffer") return this.to_buffer(pBitmap) + ; BitmapToCoimage("sharedbuffer", pBitmap, p1) + if (cotype = "sharedbuffer") + return this.to_sharedbuffer(pBitmap, p1) + ; BitmapToCoimage("screenshot", pBitmap, screenshot, alpha) if (cotype = "screenshot") return this.to_screenshot(pBitmap, p1, p2) diff --git a/ImagePut.ahk b/ImagePut.ahk index ffeb51f7..fbe8a4a2 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -105,6 +105,12 @@ ImagePutScreenshot(image, screenshot := "", alpha := "") { return ImagePut("screenshot", image, screenshot, alpha) } +; Puts the image into a file mapping and returns a buffer object sharable across processes. +; name - Global Name | string -> "Alice" +ImagePutSharedBuffer(image, name := "") { + return ImagePut("SharedBuffer", image, name) +} + ; Puts the image into a file format and returns a pointer to a stream. ; extension - File Encoding | string -> bmp, gif, jpg, png, tiff ; quality - JPEG Quality Level | integer -> 0 - 100 @@ -514,6 +520,10 @@ class ImagePut { if (cotype = "buffer") return this.to_buffer(pBitmap) + ; BitmapToCoimage("sharedbuffer", pBitmap, p1) + if (cotype = "sharedbuffer") + return this.to_sharedbuffer(pBitmap, p1) + ; BitmapToCoimage("screenshot", pBitmap, screenshot, alpha) if (cotype = "screenshot") return this.to_screenshot(pBitmap, p1, p2) From a1b0df147902dc410aaf8a506da60d76bfc83662 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 30 Apr 2023 12:03:05 -0400 Subject: [PATCH 410/492] rename --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 46b49f7b..2089b022 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1985,7 +1985,7 @@ class ImagePut { return new ImagePut.BitmapBuffer(ptr, size, width, height, free) } - read_sharedbuffer(image) { + open_sharedbuffer(image) { hMap := DllCall("OpenFileMapping", "uint", 0x2, "int", 0, "str", image, "ptr") pMap := DllCall("MapViewOfFile", "ptr", hMap, "uint", 0x2, "uint", 0, "uint", 0, "uptr", 0, "ptr") diff --git a/ImagePut.ahk b/ImagePut.ahk index fbe8a4a2..35b6e97e 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1985,7 +1985,7 @@ class ImagePut { return ImagePut.BitmapBuffer(ptr, size, width, height, free) } - static read_sharedbuffer(image) { + static open_sharedbuffer(image) { hMap := DllCall("OpenFileMapping", "uint", 0x2, "int", 0, "str", image, "ptr") pMap := DllCall("MapViewOfFile", "ptr", hMap, "uint", 0x2, "uint", 0, "uint", 0, "uptr", 0, "ptr") From f6c8dcaea406b2f362746e5cdc93b2934830ceb8 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 12 Aug 2023 12:25:58 -0400 Subject: [PATCH 411/492] change error message --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 2089b022..943cca80 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -3787,7 +3787,7 @@ class ImagePut { throw Exception("Bitmap is out of scope. `n`nIf you wish to handle raw pointers to GDI+ bitmaps, add the line" . "`n`n`t`t" this.__class ".gdiplusStartup()" . "`n`nto the top of your script. If using Gdip_All.ahk use pToken := Gdip_Startup()." - . "`nAlternatively, use pic := ImagePutBuffer() and pic.pBitmap instead." + . "`nAlternatively, use pic := ImagePutBuffer(image) and pic.pBitmap instead." . "`nYou can copy this message by pressing Ctrl + C.", -5) } } diff --git a/ImagePut.ahk b/ImagePut.ahk index 35b6e97e..e613acd9 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -3787,7 +3787,7 @@ class ImagePut { throw Error("Bitmap is out of scope. `n`nIf you wish to handle raw pointers to GDI+ bitmaps, add the line" . "`n`n`t`t" this.prototype.__class ".gdiplusStartup()" . "`n`nto the top of your script. If using Gdip_All.ahk use pToken := Gdip_Startup()." - . "`nAlternatively, use pic := ImagePutBuffer() and pic.pBitmap instead." + . "`nAlternatively, use pic := ImagePutBuffer(image) and pic.pBitmap instead." . "`nYou can copy this message by pressing Ctrl + C.", -4) } } From 4f909bb5625b6f29d0cd428e75f52d8390e0d5fd Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 4 Sep 2023 19:13:57 -0400 Subject: [PATCH 412/492] Use a static buffer to store the base64 and allocated pointers --- ImagePut (for v1).ahk | 26 ++++++++++++++++---------- ImagePut.ahk | 26 ++++++++++++++++---------- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 943cca80..76825275 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2275,12 +2275,18 @@ class ImagePut { return filepath } - Base64Put(b64) { + Base64Code(b64) { + static codes := {} + + if codes.haskey(b64) + return codes[b64] + s64 := StrLen(RTrim(b64, "=")) * 3 // 4 code := DllCall("GlobalAlloc", "uint", 0, "uptr", s64, "ptr") DllCall("crypt32\CryptStringToBinary", "str", b64, "uint", 0, "uint", 0x1, "ptr", code, "uint*", s64, "ptr", 0, "ptr", 0) DllCall("VirtualProtect", "ptr", code, "ptr", s64, "uint", 0x40, "uint*", op:=0) - return code + + return codes[b64] := code } CPUID() { @@ -2325,7 +2331,7 @@ class ImagePut { ColorKey(key := "sentinel", value := 0x00000000) { ; C source code - https://godbolt.org/z/eaG9fax9v static code := 0 - (code) || code := this.Base64Put((A_PtrSize == 4) + (code) || code := this.Base64Code((A_PtrSize == 4) ? "VYnli0UIi1UQi00UO0UMcws5EHUCiQiDwATr8F3D" : "SDnRcw5EOQF1A0SJCUiDwQTr7cM=") @@ -2339,7 +2345,7 @@ class ImagePut { SetAlpha(alpha := 0xFF) { ; C source code - https://godbolt.org/z/aWf73jTqc static code := 0 - (code) || code := this.Base64Put((A_PtrSize == 4) + (code) || code := this.Base64Code((A_PtrSize == 4) ? "VYnli0UIilUQO0UMcwiIUAODwATr813D" : "SDnRcwpEiEEDSIPBBOvxww==") @@ -2350,7 +2356,7 @@ class ImagePut { TransColor(color := "sentinel", alpha := 0x00) { ; C source code - https://godbolt.org/z/z3a8WcM5M static code := 0 - (code) || code := this.Base64Put((A_PtrSize == 4) + (code) || code := this.Base64Code((A_PtrSize == 4) ? "VYnli0UIilUUO0UMcxWLTRAzCIHh////AHUDiFADg8AE6+Zdww==" : "SDnRcxaLAUQxwKn///8AdQREiEkDSIPBBOvlww==") @@ -2364,13 +2370,13 @@ class ImagePut { PixelSearch(color, variation := 0) { ; C source code - https://godbolt.org/z/o7EPo8xPr static PixelSearch := 0 - (PixelSearch) || PixelSearch := this.Base64Put((A_PtrSize == 4) + (PixelSearch) || PixelSearch := this.Base64Code((A_PtrSize == 4) ? "VYnli1UMi00Qi0UIOdBzCTkIdAeDwATr84nQXcM=" : "SInISDnQcwtEOQB0CUiDwATr8EiJ0MM=") ; C source code - https://godbolt.org/z/4K38sq8hY static PixelSearch2 := 0 - (PixelSearch2) || PixelSearch2 := this.Base64Put((A_PtrSize == 4) + (PixelSearch2) || PixelSearch2 := this.Base64Code((A_PtrSize == 4) ? "VYnlVlNRikUQilUcik0gil0ki3UIiEX3ikUUiEX2ikUYiEX1O3UMcyiKRgI4RfdyGzpF9nIWikYBOEX1cg440HIKigY4wXIEONhzBYPGBOvTWonwW15dww==" : "VlNEilQkOESKXCRAilwkSECKdCRQSInISDnQcyuKSAJBOMhyHUQ4yXIYikgBQTjKchBEONlyC4oIOMtyBUA48XMGSIPABOvQW17D") @@ -2441,7 +2447,7 @@ class ImagePut { PixelSearchAll(color) { ; C source code - https://godbolt.org/z/zPY1qMvYe static PixelSearch3 := 0 - (PixelSearch3) || PixelSearch3 := this.Base64Put((A_PtrSize == 4) + (PixelSearch3) || PixelSearch3 := this.Base64Code((A_PtrSize == 4) ? "VTHAieVTi1UQi00UOcpzGItdGDkadQw7RQxzBotdCIkUg0CDwgTr5Ftdww==" : "McBEi1QkKE05yHMYRTkQdQ050HMHQYnDTokE2f/ASYPABOvjww==") @@ -2477,7 +2483,7 @@ class ImagePut { ImageSearch(image) { ; C source code - https://godbolt.org/z/qPodGdP1d static code := 0 - (code) || code := this.Base64Put((A_PtrSize == 4) + (code) || code := this.Base64Code((A_PtrSize == 4) ? "VYnlV1ZTg+wUi0UMi1UYi00IjTyFAAAAAItFECtFHA+vxwNFCIlF6ItFDCnQiUXkjQSVAAAAAIlF7ItF6DnBc2eLRRSLADkBdAmL" . "RRSAeAMAdVCJyCtFCDHSwfgC93UMOVXkfD4x0otFFInLiVXwi3XwO3UcdDyLVeyJ3gHCiVXgi1XgOdBzFIB4AwB0BosWORB1D4PA" . "BIPGBOvl/0XwAfvrzIPBBOuSi0UQD6/HA0UIicGDxBSJyFteX13D" @@ -2505,7 +2511,7 @@ class ImagePut { ImageSearchAll(image) { ; C source code - https://godbolt.org/z/qPodGdP1d static code := 0 - (code) || code := this.Base64Put((A_PtrSize == 4) + (code) || code := this.Base64Code((A_PtrSize == 4) ? "VYnlV1ZTg+wUi0UMi1UYi00IjTyFAAAAAItFECtFHA+vxwNFCIlF6ItFDCnQiUXkjQSVAAAAAIlF7ItF6DnBc2eLRRSLADkBdAmL" . "RRSAeAMAdVCJyCtFCDHSwfgC93UMOVXkfD4x0otFFInLiVXwi3XwO3UcdDyLVeyJ3gHCiVXgi1XgOdBzFIB4AwB0BosWORB1D4PA" . "BIPGBOvl/0XwAfvrzIPBBOuSi0UQD6/HA0UIicGDxBSJyFteX13D" diff --git a/ImagePut.ahk b/ImagePut.ahk index e613acd9..e569c313 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2275,12 +2275,18 @@ class ImagePut { return filepath } - Base64Put(b64) { + Base64Code(b64) { + static codes := Map() + + if codes.has(b64) + return codes[b64] + s64 := StrLen(RTrim(b64, "=")) * 3 // 4 code := DllCall("GlobalAlloc", "uint", 0, "uptr", s64, "ptr") DllCall("crypt32\CryptStringToBinary", "str", b64, "uint", 0, "uint", 0x1, "ptr", code, "uint*", s64, "ptr", 0, "ptr", 0) DllCall("VirtualProtect", "ptr", code, "ptr", s64, "uint", 0x40, "uint*", &op:=0) - return code + + return codes[b64] := code } CPUID() { @@ -2325,7 +2331,7 @@ class ImagePut { ColorKey(key := "sentinel", value := 0x00000000) { ; C source code - https://godbolt.org/z/eaG9fax9v static code := 0 - (code) || code := this.Base64Put((A_PtrSize == 4) + (code) || code := this.Base64Code((A_PtrSize == 4) ? "VYnli0UIi1UQi00UO0UMcws5EHUCiQiDwATr8F3D" : "SDnRcw5EOQF1A0SJCUiDwQTr7cM=") @@ -2339,7 +2345,7 @@ class ImagePut { SetAlpha(alpha := 0xFF) { ; C source code - https://godbolt.org/z/aWf73jTqc static code := 0 - (code) || code := this.Base64Put((A_PtrSize == 4) + (code) || code := this.Base64Code((A_PtrSize == 4) ? "VYnli0UIilUQO0UMcwiIUAODwATr813D" : "SDnRcwpEiEEDSIPBBOvxww==") @@ -2350,7 +2356,7 @@ class ImagePut { TransColor(color := "sentinel", alpha := 0x00) { ; C source code - https://godbolt.org/z/z3a8WcM5M static code := 0 - (code) || code := this.Base64Put((A_PtrSize == 4) + (code) || code := this.Base64Code((A_PtrSize == 4) ? "VYnli0UIilUUO0UMcxWLTRAzCIHh////AHUDiFADg8AE6+Zdww==" : "SDnRcxaLAUQxwKn///8AdQREiEkDSIPBBOvlww==") @@ -2364,13 +2370,13 @@ class ImagePut { PixelSearch(color, variation := 0) { ; C source code - https://godbolt.org/z/o7EPo8xPr static PixelSearch := 0 - (PixelSearch) || PixelSearch := this.Base64Put((A_PtrSize == 4) + (PixelSearch) || PixelSearch := this.Base64Code((A_PtrSize == 4) ? "VYnli1UMi00Qi0UIOdBzCTkIdAeDwATr84nQXcM=" : "SInISDnQcwtEOQB0CUiDwATr8EiJ0MM=") ; C source code - https://godbolt.org/z/4K38sq8hY static PixelSearch2 := 0 - (PixelSearch2) || PixelSearch2 := this.Base64Put((A_PtrSize == 4) + (PixelSearch2) || PixelSearch2 := this.Base64Code((A_PtrSize == 4) ? "VYnlVlNRikUQilUcik0gil0ki3UIiEX3ikUUiEX2ikUYiEX1O3UMcyiKRgI4RfdyGzpF9nIWikYBOEX1cg440HIKigY4wXIEONhzBYPGBOvTWonwW15dww==" : "VlNEilQkOESKXCRAilwkSECKdCRQSInISDnQcyuKSAJBOMhyHUQ4yXIYikgBQTjKchBEONlyC4oIOMtyBUA48XMGSIPABOvQW17D") @@ -2441,7 +2447,7 @@ class ImagePut { PixelSearchAll(color) { ; C source code - https://godbolt.org/z/zPY1qMvYe static PixelSearch3 := 0 - (PixelSearch3) || PixelSearch3 := this.Base64Put((A_PtrSize == 4) + (PixelSearch3) || PixelSearch3 := this.Base64Code((A_PtrSize == 4) ? "VTHAieVTi1UQi00UOcpzGItdGDkadQw7RQxzBotdCIkUg0CDwgTr5Ftdww==" : "McBEi1QkKE05yHMYRTkQdQ050HMHQYnDTokE2f/ASYPABOvjww==") @@ -2477,7 +2483,7 @@ class ImagePut { ImageSearch(image) { ; C source code - https://godbolt.org/z/qPodGdP1d static code := 0 - (code) || code := this.Base64Put((A_PtrSize == 4) + (code) || code := this.Base64Code((A_PtrSize == 4) ? "VYnlV1ZTg+wUi0UMi1UYi00IjTyFAAAAAItFECtFHA+vxwNFCIlF6ItFDCnQiUXkjQSVAAAAAIlF7ItF6DnBc2eLRRSLADkBdAmL" . "RRSAeAMAdVCJyCtFCDHSwfgC93UMOVXkfD4x0otFFInLiVXwi3XwO3UcdDyLVeyJ3gHCiVXgi1XgOdBzFIB4AwB0BosWORB1D4PA" . "BIPGBOvl/0XwAfvrzIPBBOuSi0UQD6/HA0UIicGDxBSJyFteX13D" @@ -2505,7 +2511,7 @@ class ImagePut { ImageSearchAll(image) { ; C source code - https://godbolt.org/z/qPodGdP1d static code := 0 - (code) || code := this.Base64Put((A_PtrSize == 4) + (code) || code := this.Base64Code((A_PtrSize == 4) ? "VYnlV1ZTg+wUi0UMi1UYi00IjTyFAAAAAItFECtFHA+vxwNFCIlF6ItFDCnQiUXkjQSVAAAAAIlF7ItF6DnBc2eLRRSLADkBdAmL" . "RRSAeAMAdVCJyCtFCDHSwfgC93UMOVXkfD4x0otFFInLiVXwi3XwO3UcdDyLVeyJ3gHCiVXgi1XgOdBzFIB4AwB0BosWORB1D4PA" . "BIPGBOvl/0XwAfvrzIPBBOuSi0UQD6/HA0UIicGDxBSJyFteX13D" From 3b1cb71351dd7a50444e69e84e94e38653c5eab1 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 4 Sep 2023 19:33:38 -0400 Subject: [PATCH 413/492] Remove statics holding onto the machine code --- ImagePut (for v1).ahk | 24 ++++++++---------------- ImagePut.ahk | 24 ++++++++---------------- 2 files changed, 16 insertions(+), 32 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 76825275..8cf99aee 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2330,8 +2330,7 @@ class ImagePut { ColorKey(key := "sentinel", value := 0x00000000) { ; C source code - https://godbolt.org/z/eaG9fax9v - static code := 0 - (code) || code := this.Base64Code((A_PtrSize == 4) + code := this.Base64Code((A_PtrSize == 4) ? "VYnli0UIi1UQi00UO0UMcws5EHUCiQiDwATr8F3D" : "SDnRcw5EOQF1A0SJCUiDwQTr7cM=") @@ -2344,8 +2343,7 @@ class ImagePut { SetAlpha(alpha := 0xFF) { ; C source code - https://godbolt.org/z/aWf73jTqc - static code := 0 - (code) || code := this.Base64Code((A_PtrSize == 4) + code := this.Base64Code((A_PtrSize == 4) ? "VYnli0UIilUQO0UMcwiIUAODwATr813D" : "SDnRcwpEiEEDSIPBBOvxww==") @@ -2355,8 +2353,7 @@ class ImagePut { TransColor(color := "sentinel", alpha := 0x00) { ; C source code - https://godbolt.org/z/z3a8WcM5M - static code := 0 - (code) || code := this.Base64Code((A_PtrSize == 4) + code := this.Base64Code((A_PtrSize == 4) ? "VYnli0UIilUUO0UMcxWLTRAzCIHh////AHUDiFADg8AE6+Zdww==" : "SDnRcxaLAUQxwKn///8AdQREiEkDSIPBBOvlww==") @@ -2369,14 +2366,12 @@ class ImagePut { PixelSearch(color, variation := 0) { ; C source code - https://godbolt.org/z/o7EPo8xPr - static PixelSearch := 0 - (PixelSearch) || PixelSearch := this.Base64Code((A_PtrSize == 4) + PixelSearch := this.Base64Code((A_PtrSize == 4) ? "VYnli1UMi00Qi0UIOdBzCTkIdAeDwATr84nQXcM=" : "SInISDnQcwtEOQB0CUiDwATr8EiJ0MM=") ; C source code - https://godbolt.org/z/4K38sq8hY - static PixelSearch2 := 0 - (PixelSearch2) || PixelSearch2 := this.Base64Code((A_PtrSize == 4) + PixelSearch2 := this.Base64Code((A_PtrSize == 4) ? "VYnlVlNRikUQilUcik0gil0ki3UIiEX3ikUUiEX2ikUYiEX1O3UMcyiKRgI4RfdyGzpF9nIWikYBOEX1cg440HIKigY4wXIEONhzBYPGBOvTWonwW15dww==" : "VlNEilQkOESKXCRAilwkSECKdCRQSInISDnQcyuKSAJBOMhyHUQ4yXIYikgBQTjKchBEONlyC4oIOMtyBUA48XMGSIPABOvQW17D") @@ -2446,8 +2441,7 @@ class ImagePut { PixelSearchAll(color) { ; C source code - https://godbolt.org/z/zPY1qMvYe - static PixelSearch3 := 0 - (PixelSearch3) || PixelSearch3 := this.Base64Code((A_PtrSize == 4) + PixelSearch3 := this.Base64Code((A_PtrSize == 4) ? "VTHAieVTi1UQi00UOcpzGItdGDkadQw7RQxzBotdCIkUg0CDwgTr5Ftdww==" : "McBEi1QkKE05yHMYRTkQdQ050HMHQYnDTokE2f/ASYPABOvjww==") @@ -2482,8 +2476,7 @@ class ImagePut { ImageSearch(image) { ; C source code - https://godbolt.org/z/qPodGdP1d - static code := 0 - (code) || code := this.Base64Code((A_PtrSize == 4) + code := this.Base64Code((A_PtrSize == 4) ? "VYnlV1ZTg+wUi0UMi1UYi00IjTyFAAAAAItFECtFHA+vxwNFCIlF6ItFDCnQiUXkjQSVAAAAAIlF7ItF6DnBc2eLRRSLADkBdAmL" . "RRSAeAMAdVCJyCtFCDHSwfgC93UMOVXkfD4x0otFFInLiVXwi3XwO3UcdDyLVeyJ3gHCiVXgi1XgOdBzFIB4AwB0BosWORB1D4PA" . "BIPGBOvl/0XwAfvrzIPBBOuSi0UQD6/HA0UIicGDxBSJyFteX13D" @@ -2510,8 +2503,7 @@ class ImagePut { ImageSearchAll(image) { ; C source code - https://godbolt.org/z/qPodGdP1d - static code := 0 - (code) || code := this.Base64Code((A_PtrSize == 4) + code := this.Base64Code((A_PtrSize == 4) ? "VYnlV1ZTg+wUi0UMi1UYi00IjTyFAAAAAItFECtFHA+vxwNFCIlF6ItFDCnQiUXkjQSVAAAAAIlF7ItF6DnBc2eLRRSLADkBdAmL" . "RRSAeAMAdVCJyCtFCDHSwfgC93UMOVXkfD4x0otFFInLiVXwi3XwO3UcdDyLVeyJ3gHCiVXgi1XgOdBzFIB4AwB0BosWORB1D4PA" . "BIPGBOvl/0XwAfvrzIPBBOuSi0UQD6/HA0UIicGDxBSJyFteX13D" diff --git a/ImagePut.ahk b/ImagePut.ahk index e569c313..fdeed617 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2330,8 +2330,7 @@ class ImagePut { ColorKey(key := "sentinel", value := 0x00000000) { ; C source code - https://godbolt.org/z/eaG9fax9v - static code := 0 - (code) || code := this.Base64Code((A_PtrSize == 4) + code := this.Base64Code((A_PtrSize == 4) ? "VYnli0UIi1UQi00UO0UMcws5EHUCiQiDwATr8F3D" : "SDnRcw5EOQF1A0SJCUiDwQTr7cM=") @@ -2344,8 +2343,7 @@ class ImagePut { SetAlpha(alpha := 0xFF) { ; C source code - https://godbolt.org/z/aWf73jTqc - static code := 0 - (code) || code := this.Base64Code((A_PtrSize == 4) + code := this.Base64Code((A_PtrSize == 4) ? "VYnli0UIilUQO0UMcwiIUAODwATr813D" : "SDnRcwpEiEEDSIPBBOvxww==") @@ -2355,8 +2353,7 @@ class ImagePut { TransColor(color := "sentinel", alpha := 0x00) { ; C source code - https://godbolt.org/z/z3a8WcM5M - static code := 0 - (code) || code := this.Base64Code((A_PtrSize == 4) + code := this.Base64Code((A_PtrSize == 4) ? "VYnli0UIilUUO0UMcxWLTRAzCIHh////AHUDiFADg8AE6+Zdww==" : "SDnRcxaLAUQxwKn///8AdQREiEkDSIPBBOvlww==") @@ -2369,14 +2366,12 @@ class ImagePut { PixelSearch(color, variation := 0) { ; C source code - https://godbolt.org/z/o7EPo8xPr - static PixelSearch := 0 - (PixelSearch) || PixelSearch := this.Base64Code((A_PtrSize == 4) + PixelSearch := this.Base64Code((A_PtrSize == 4) ? "VYnli1UMi00Qi0UIOdBzCTkIdAeDwATr84nQXcM=" : "SInISDnQcwtEOQB0CUiDwATr8EiJ0MM=") ; C source code - https://godbolt.org/z/4K38sq8hY - static PixelSearch2 := 0 - (PixelSearch2) || PixelSearch2 := this.Base64Code((A_PtrSize == 4) + PixelSearch2 := this.Base64Code((A_PtrSize == 4) ? "VYnlVlNRikUQilUcik0gil0ki3UIiEX3ikUUiEX2ikUYiEX1O3UMcyiKRgI4RfdyGzpF9nIWikYBOEX1cg440HIKigY4wXIEONhzBYPGBOvTWonwW15dww==" : "VlNEilQkOESKXCRAilwkSECKdCRQSInISDnQcyuKSAJBOMhyHUQ4yXIYikgBQTjKchBEONlyC4oIOMtyBUA48XMGSIPABOvQW17D") @@ -2446,8 +2441,7 @@ class ImagePut { PixelSearchAll(color) { ; C source code - https://godbolt.org/z/zPY1qMvYe - static PixelSearch3 := 0 - (PixelSearch3) || PixelSearch3 := this.Base64Code((A_PtrSize == 4) + PixelSearch3 := this.Base64Code((A_PtrSize == 4) ? "VTHAieVTi1UQi00UOcpzGItdGDkadQw7RQxzBotdCIkUg0CDwgTr5Ftdww==" : "McBEi1QkKE05yHMYRTkQdQ050HMHQYnDTokE2f/ASYPABOvjww==") @@ -2482,8 +2476,7 @@ class ImagePut { ImageSearch(image) { ; C source code - https://godbolt.org/z/qPodGdP1d - static code := 0 - (code) || code := this.Base64Code((A_PtrSize == 4) + code := this.Base64Code((A_PtrSize == 4) ? "VYnlV1ZTg+wUi0UMi1UYi00IjTyFAAAAAItFECtFHA+vxwNFCIlF6ItFDCnQiUXkjQSVAAAAAIlF7ItF6DnBc2eLRRSLADkBdAmL" . "RRSAeAMAdVCJyCtFCDHSwfgC93UMOVXkfD4x0otFFInLiVXwi3XwO3UcdDyLVeyJ3gHCiVXgi1XgOdBzFIB4AwB0BosWORB1D4PA" . "BIPGBOvl/0XwAfvrzIPBBOuSi0UQD6/HA0UIicGDxBSJyFteX13D" @@ -2510,8 +2503,7 @@ class ImagePut { ImageSearchAll(image) { ; C source code - https://godbolt.org/z/qPodGdP1d - static code := 0 - (code) || code := this.Base64Code((A_PtrSize == 4) + code := this.Base64Code((A_PtrSize == 4) ? "VYnlV1ZTg+wUi0UMi1UYi00IjTyFAAAAAItFECtFHA+vxwNFCIlF6ItFDCnQiUXkjQSVAAAAAIlF7ItF6DnBc2eLRRSLADkBdAmL" . "RRSAeAMAdVCJyCtFCDHSwfgC93UMOVXkfD4x0otFFInLiVXwi3XwO3UcdDyLVeyJ3gHCiVXgi1XgOdBzFIB4AwB0BosWORB1D4PA" . "BIPGBOvl/0XwAfvrzIPBBOuSi0UQD6/HA0UIicGDxBSJyFteX13D" From b8a6a4cf5f0cd97bb42ab28ee8b58444995c87ab Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 4 Sep 2023 20:20:23 -0400 Subject: [PATCH 414/492] comments for pixelsearch --- ImagePut (for v1).ahk | 8 ++++---- ImagePut.ahk | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 8cf99aee..8f7f6f66 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2378,11 +2378,11 @@ class ImagePut { ; Lift color to 32-bits if first 8 bits are zero. (color >> 24) || color |= 0xFF000000 - ; PixelSearch, single color, no variation + ; PixelSearch, single color with no variation if !IsObject(variation) && (variation == 0) byte := DllCall(PixelSearch, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "cdecl ptr") - ; PixelSearch, single color, and variation + ; PixelSearch, single color with single variation else if !IsObject(variation) && (variation != 0) { r := ((color & 0xFF0000) >> 16) g := ((color & 0xFF00) >> 8) @@ -2400,7 +2400,7 @@ class ImagePut { , "cdecl ptr") } - ; PixelSearch, range of colors, and variation. + ; PixelSearch, single color with multiple variation. else if IsObject(variation) && (variation.length() == 3) { r := ((color & 0xFF0000) >> 16) g := ((color & 0xFF00) >> 8) @@ -2416,7 +2416,7 @@ class ImagePut { , "cdecl ptr") } - ; PixelSearch, range of colors, and variation. + ; PixelSearch, range of colors. else if IsObject(variation) && (variation.length() == 6) { byte := DllCall(PixelSearch2, "ptr", this.ptr, "ptr", this.ptr + this.size , "uchar", min(max(variation[1], variation[2]), 255) diff --git a/ImagePut.ahk b/ImagePut.ahk index fdeed617..dea3c750 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2378,11 +2378,11 @@ class ImagePut { ; Lift color to 32-bits if first 8 bits are zero. (color >> 24) || color |= 0xFF000000 - ; PixelSearch, single color, no variation + ; PixelSearch, single color with no variation if !IsObject(variation) && (variation == 0) byte := DllCall(PixelSearch, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "cdecl ptr") - ; PixelSearch, single color, and variation + ; PixelSearch, single color with single variation else if !IsObject(variation) && (variation != 0) { r := ((color & 0xFF0000) >> 16) g := ((color & 0xFF00) >> 8) @@ -2400,7 +2400,7 @@ class ImagePut { , "cdecl ptr") } - ; PixelSearch, range of colors, and variation. + ; PixelSearch, single color with multiple variation. else if IsObject(variation) && (variation.length == 3) { r := ((color & 0xFF0000) >> 16) g := ((color & 0xFF00) >> 8) @@ -2416,7 +2416,7 @@ class ImagePut { , "cdecl ptr") } - ; PixelSearch, range of colors, and variation. + ; PixelSearch, range of colors. else if IsObject(variation) && (variation.length == 6) { byte := DllCall(PixelSearch2, "ptr", this.ptr, "ptr", this.ptr + this.size , "uchar", min(max(variation[1], variation[2]), 255) From 75ea52d6b625153c540cbb0e0f00903d5cc3da1a Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 4 Sep 2023 20:29:25 -0400 Subject: [PATCH 415/492] C source files --- source/imagesearch3.c | 55 ++++++++++++++++++++++++++++++++++++++++ source/pixelsearchall.c | 12 +++++++++ source/pixelsearchall2.c | 16 ++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 source/imagesearch3.c create mode 100644 source/pixelsearchall.c create mode 100644 source/pixelsearchall2.c diff --git a/source/imagesearch3.c b/source/imagesearch3.c new file mode 100644 index 00000000..1ebb3df1 --- /dev/null +++ b/source/imagesearch3.c @@ -0,0 +1,55 @@ +unsigned int imagesearch(unsigned int ** result, unsigned int capacity, unsigned int * start, unsigned int width, unsigned int height, unsigned int * s, unsigned int w, unsigned int h) { + // width, height, start, current, end refer to the haystack (main image) + // x, y, w, h, s, c, e refer to the needle (search image) + unsigned int count = 0; + unsigned int * current = start; + unsigned int * end = start + width * (height - h); // Remaining area must be greater than search height + + int range_x = width - w; + int range_y = height - h; // optimized away + + int x, y, offset; + unsigned int * c; + unsigned int * e; + unsigned int * p; + + // Start off searching with pointers. + while (current < end) { + + // Check if the current pixel matches the first pixel of subimage. + if (*current == *s || *((unsigned char *) s + 3) == 0) { // just continue if search image is transparent + + // Convert current pointer to (x, y). + offset = current - start; + x = offset % width; + y = offset / width; // optimized away + + // Check if (x, y) exceeds bounds. + if (x > range_x) // range_y check is done above + goto next; + + // Subimage loop. + c = s; + for (int i = 0; i < h; i++) { + p = current + width * i; + e = c + w; + while (c < e) { + if (*((unsigned char *) c + 3)) { // skip transparent pixels in search image + if (*c != *p) + goto next; + } + c++; // Here simply incrementing will interate the entire image + p++; // Will be reset each run + } + } + + // Found matching image! + if (count < capacity) + *(result + count) = current; + count++; + } + next: + current++; + } + return count; +} \ No newline at end of file diff --git a/source/pixelsearchall.c b/source/pixelsearchall.c new file mode 100644 index 00000000..ea100f9c --- /dev/null +++ b/source/pixelsearchall.c @@ -0,0 +1,12 @@ +unsigned int pixelsearchall(unsigned int ** result, unsigned int capacity, unsigned int * start, unsigned int * end, unsigned int color) { + unsigned int count = 0; + while (start < end) { + if (*start == color) { + if (count < capacity) + *(result + count) = start; + count++; + } + start++; + } + return count; +} \ No newline at end of file diff --git a/source/pixelsearchall2.c b/source/pixelsearchall2.c new file mode 100644 index 00000000..92a118e0 --- /dev/null +++ b/source/pixelsearchall2.c @@ -0,0 +1,16 @@ +unsigned int pixelsearchall2(unsigned int ** result, unsigned int capacity, unsigned int * start, unsigned int * end, unsigned char rh, unsigned char rl, unsigned char gh, unsigned char gl, unsigned char bh, unsigned char bl) { + unsigned int count = 0; + unsigned char r, g, b; + while (start < end) { + r = *((unsigned char *) start + 2); + g = *((unsigned char *) start + 1); + b = *((unsigned char *) start + 0); + if (rh >= r && r >= rl && gh >= g && g >= gl && bh >= b && b >= bl) { + if (count < capacity) + *(result + count) = start; + count++; + } + start++; + } + return count; +} \ No newline at end of file From 8f65a5b5a838bb15c07e611cdbecc3871b0141df Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 4 Sep 2023 20:30:46 -0400 Subject: [PATCH 416/492] C source files --- source/imagesearchall.c | 55 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 source/imagesearchall.c diff --git a/source/imagesearchall.c b/source/imagesearchall.c new file mode 100644 index 00000000..68d3869b --- /dev/null +++ b/source/imagesearchall.c @@ -0,0 +1,55 @@ +unsigned int imagesearchall(unsigned int ** result, unsigned int capacity, unsigned int * start, unsigned int width, unsigned int height, unsigned int * s, unsigned int w, unsigned int h) { + // width, height, start, current, end refer to the haystack (main image) + // x, y, w, h, s, c, e refer to the needle (search image) + unsigned int count = 0; + unsigned int * current = start; + unsigned int * end = start + width * (height - h); // Remaining area must be greater than search height + + int range_x = width - w; + int range_y = height - h; // optimized away + + int x, y, offset; + unsigned int * c; + unsigned int * e; + unsigned int * p; + + // Start off searching with pointers. + while (current < end) { + + // Check if the current pixel matches the first pixel of subimage. + if (*current == *s || *((unsigned char *) s + 3) == 0) { // just continue if search image is transparent + + // Convert current pointer to (x, y). + offset = current - start; + x = offset % width; + y = offset / width; // optimized away + + // Check if (x, y) exceeds bounds. + if (x > range_x) // range_y check is done above + goto next; + + // Subimage loop. + c = s; + for (int i = 0; i < h; i++) { + p = current + width * i; + e = c + w; + while (c < e) { + if (*((unsigned char *) c + 3)) { // skip transparent pixels in search image + if (*c != *p) + goto next; + } + c++; // Here simply incrementing will interate the entire image + p++; // Will be reset each run + } + } + + // Found matching image! + if (count < capacity) + *(result + count) = current; + count++; + } + next: + current++; + } + return count; +} \ No newline at end of file From cea9e37234d2cc3b12642578b7751fc199867e32 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 4 Sep 2023 23:34:16 -0400 Subject: [PATCH 417/492] Refactor PixelSearch --- ImagePut (for v1).ahk | 165 +++++++++++++++++++++++++++++++++------- ImagePut.ahk | 173 ++++++++++++++++++++++++++++++++++-------- 2 files changed, 276 insertions(+), 62 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 8f7f6f66..9a36bf4c 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2365,32 +2365,76 @@ class ImagePut { } PixelSearch(color, variation := 0) { - ; C source code - https://godbolt.org/z/o7EPo8xPr - PixelSearch := this.Base64Code((A_PtrSize == 4) - ? "VYnli1UMi00Qi0UIOdBzCTkIdAeDwATr84nQXcM=" - : "SInISDnQcwtEOQB0CUiDwATr8EiJ0MM=") - ; C source code - https://godbolt.org/z/4K38sq8hY - PixelSearch2 := this.Base64Code((A_PtrSize == 4) + ; Option 1: PixelSearch, single color with no variation. + ; Option 2: PixelSearch, single color with single variation. + ; Option 3: PixelSearch, single color with multiple variation. + ; Option 4: PixelSearch, range of colors. + ; Option 5: PixelSearch, multiple colors with no variation. + ; Option 6: PixelSearch, multiple colors with single variation. + ; Option 7: PixelSearch, multiple colors with multiple variation. + + if not IsObject(color) { + + ; Lift color to 32-bits if first 8 bits are zero. + (color >> 24) || color |= 0xFF000000 + + if not IsObject(variation) + if (variation == 0) + option := 1 + else + option := 2 + else if (variation.length() == 3) + option := 3 + else if (variation.length() == 6) + option := 4 + else throw Exception("Invalid variation parameter.") + } + else + if not IsObject(variation) + if (variation == 0) + option := 5 + else + option := 6 + else if (variation.length() == 3) + option := 7 + else throw Exception("Invalid variation parameter.") + + ; ---------------------------- Machine code generated with MCode4GCC using gcc 13.2.0 ---------------------------- + + ; C source code - https://godbolt.org/z/n8894d9oG + pixelsearch := this.Base64Code((A_PtrSize == 4) + ? "VYnli1UMi00Qi0UIOdBzCTkIdAWDwATr813D" + : "SInISDnQcwtEOQB0BkiDwATr8MM=") + + ; C source code - https://godbolt.org/z/19TM9Gzo5 + pixelsearch2 := this.Base64Code((A_PtrSize == 4) ? "VYnlVlNRikUQilUcik0gil0ki3UIiEX3ikUUiEX2ikUYiEX1O3UMcyiKRgI4RfdyGzpF9nIWikYBOEX1cg440HIKigY4wXIEONhzBYPGBOvTWonwW15dww==" : "VlNEilQkOESKXCRAilwkSECKdCRQSInISDnQcyuKSAJBOMhyHUQ4yXIYikgBQTjKchBEONlyC4oIOMtyBUA48XMGSIPABOvQW17D") - ; Lift color to 32-bits if first 8 bits are zero. - (color >> 24) || color |= 0xFF000000 + ; C source code - https://godbolt.org/z/4hEhb7vG8 + pixelsearch3 := this.Base64Code((A_PtrSize == 4) + ? "VYnlU4tNDItFCDnIcxkx0jtVFHQNi10QixyTORh0CELr7oPABOvjW13D" + : "SInISDnQcxwxyUQ5yXMPSP/BRYtUiPxEORB17usGSIPABOvfww==") - ; PixelSearch, single color with no variation - if !IsObject(variation) && (variation == 0) - byte := DllCall(PixelSearch, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "cdecl ptr") + ; C source code - https://godbolt.org/z/oEGGeedac + pixelsearch4 := this.Base64Code((A_PtrSize == 4) + ? "VYnlV1ZTUYt1EIt9FItVCDtVDHNFikICiloBiEXzigKIRfIxwDtFGHQrik3zOEyGAnIfOkyHAnIZOFyGAXITOlyHAXINik3yOAyGcgU6DIdzCEDr0IPCBOu2idBaW15fXcM=" + : "U0iJyEg50HNFRIpQAkSKWAExyYoYO0wkMHMtRThUiAJyIUU6VIkCchpFOFyIAXITRTpciQFyDEE4HIhyBkE6HIlzC0j/wevNSIPABOu2W8M=") - ; PixelSearch, single color with single variation - else if !IsObject(variation) && (variation != 0) { + ; ---------------------------------------------------------------------------------------------------------------- + + if (option == 1) + ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. + byte := DllCall(pixelsearch, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "cdecl ptr") + + if (option == 2) { r := ((color & 0xFF0000) >> 16) g := ((color & 0xFF00) >> 8) b := ((color & 0xFF)) v := abs(variation) - ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. - byte := DllCall(PixelSearch2, "ptr", this.ptr, "ptr", this.ptr + this.size + byte := DllCall(pixelsearch2, "ptr", this.ptr, "ptr", this.ptr + this.size , "uchar", min(r+v, 255) , "uchar", max(r-v, 0) , "uchar", min(g+v, 255) @@ -2400,25 +2444,26 @@ class ImagePut { , "cdecl ptr") } - ; PixelSearch, single color with multiple variation. - else if IsObject(variation) && (variation.length() == 3) { + if (option == 3) { r := ((color & 0xFF0000) >> 16) g := ((color & 0xFF00) >> 8) b := ((color & 0xFF)) - - byte := DllCall(PixelSearch2, "ptr", this.ptr, "ptr", this.ptr + this.size - , "uchar", min(r + variation[1], 255) - , "uchar", max(r - variation[1], 0) - , "uchar", min(g + variation[2], 255) - , "uchar", max(g - variation[2], 0) - , "uchar", min(b + variation[3], 255) - , "uchar", max(b - variation[3], 0) + vr := abs(variation[1]) + vg := abs(variation[2]) + vb := abs(variation[3]) + + byte := DllCall(pixelsearch2, "ptr", this.ptr, "ptr", this.ptr + this.size + , "uchar", min(r + vr, 255) + , "uchar", max(r - vr, 0) + , "uchar", min(g + vg, 255) + , "uchar", max(g - vg, 0) + , "uchar", min(b + vb, 255) + , "uchar", max(b - vb, 0) , "cdecl ptr") } - ; PixelSearch, range of colors. - else if IsObject(variation) && (variation.length() == 6) { - byte := DllCall(PixelSearch2, "ptr", this.ptr, "ptr", this.ptr + this.size + if (option == 4) + byte := DllCall(pixelsearch2, "ptr", this.ptr, "ptr", this.ptr + this.size , "uchar", min(max(variation[1], variation[2]), 255) , "uchar", max(min(variation[1], variation[2]), 0) , "uchar", min(max(variation[3], variation[4]), 255) @@ -2426,9 +2471,71 @@ class ImagePut { , "uchar", min(max(variation[5], variation[6]), 255) , "uchar", max(min(variation[5], variation[6]), 0) , "cdecl ptr") + + if (option == 5) { + ; Create a struct of unsigned integers. + VarSetCapacity(colors, 4*color.length()) + + ; Fill the struct by iterating through the input array. + for i, c in color { + (c >> 24) || c |= 0xFF000000 ; Lift colors to 32-bit ARGB. + NumPut(c, colors, 4*(A_Index-1), "uint") ; Place the unsigned int at each offset. + } + + byte := DllCall(pixelsearch3, "ptr", this.ptr, "ptr", this.ptr + this.size, "ptr", &colors, "uint", color.length(), "cdecl ptr") } - else throw Exception("Invalid variation parameter.") + ; Options 6 & 7 - Creates a high and low struct where each pair is the min and max range. + + if (option == 6) { + VarSetCapacity(high, 4*color.length()) + VarSetCapacity(low, 4*color.length()) + + for i, c in color { + A_Offset := A_Index - 1 + + r := ((c & 0xFF0000) >> 16) + g := ((c & 0xFF00) >> 8) + b := ((c & 0xFF)) + v := abs(variation) + + NumPut(min(r+v, 255), high, 4*A_Offset + 2, "uchar") + NumPut(min(g+v, 255), high, 4*A_Offset + 1, "uchar") + NumPut(min(b+v, 255), high, 4*A_Offset + 0, "uchar") + + NumPut(max(r-v, 0), low, 4*A_Offset + 2, "uchar") + NumPut(max(g-v, 0), low, 4*A_Offset + 1, "uchar") + NumPut(max(b-v, 0), low, 4*A_Offset + 0, "uchar") + } + + byte := DllCall(pixelsearch4, "ptr", this.ptr, "ptr", this.ptr + this.size, "ptr", &high, "ptr", &low, "uint", color.length(), "cdecl ptr") + } + + if (option == 7) { + VarSetCapacity(high, 4*color.length()) + VarSetCapacity(low, 4*color.length()) + + for i, c in color { + A_Offset := A_Index - 1 + + r := ((c & 0xFF0000) >> 16) + g := ((c & 0xFF00) >> 8) + b := ((c & 0xFF)) + vr := abs(variation[1]) + vg := abs(variation[2]) + vb := abs(variation[3]) + + NumPut(min(r + vr, 255), high, 4*A_Offset + 2, "uchar") + NumPut(min(g + vg, 255), high, 4*A_Offset + 1, "uchar") + NumPut(min(b + vb, 255), high, 4*A_Offset + 0, "uchar") + + NumPut(max(r - vr, 0), low, 4*A_Offset + 2, "uchar") + NumPut(max(g - vg, 0), low, 4*A_Offset + 1, "uchar") + NumPut(max(b - vb, 0), low, 4*A_Offset + 0, "uchar") + } + + byte := DllCall(pixelsearch4, "ptr", this.ptr, "ptr", this.ptr + this.size, "ptr", &high, "ptr", &low, "uint", color.length(), "cdecl ptr") + } ; Compare the address to the out-of-bounds limit. if (byte == this.ptr + this.size) diff --git a/ImagePut.ahk b/ImagePut.ahk index dea3c750..813bf440 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1126,7 +1126,7 @@ class ImagePut { } - + ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") @@ -2280,7 +2280,7 @@ class ImagePut { if codes.has(b64) return codes[b64] - + s64 := StrLen(RTrim(b64, "=")) * 3 // 4 code := DllCall("GlobalAlloc", "uint", 0, "uptr", s64, "ptr") DllCall("crypt32\CryptStringToBinary", "str", b64, "uint", 0, "uint", 0x1, "ptr", code, "uint*", s64, "ptr", 0, "ptr", 0) @@ -2365,32 +2365,76 @@ class ImagePut { } PixelSearch(color, variation := 0) { - ; C source code - https://godbolt.org/z/o7EPo8xPr - PixelSearch := this.Base64Code((A_PtrSize == 4) - ? "VYnli1UMi00Qi0UIOdBzCTkIdAeDwATr84nQXcM=" - : "SInISDnQcwtEOQB0CUiDwATr8EiJ0MM=") - ; C source code - https://godbolt.org/z/4K38sq8hY - PixelSearch2 := this.Base64Code((A_PtrSize == 4) + ; Option 1: PixelSearch, single color with no variation. + ; Option 2: PixelSearch, single color with single variation. + ; Option 3: PixelSearch, single color with multiple variation. + ; Option 4: PixelSearch, range of colors. + ; Option 5: PixelSearch, multiple colors with no variation. + ; Option 6: PixelSearch, multiple colors with single variation. + ; Option 7: PixelSearch, multiple colors with multiple variation. + + if not IsObject(color) { + + ; Lift color to 32-bits if first 8 bits are zero. + (color >> 24) || color |= 0xFF000000 + + if not IsObject(variation) + if (variation == 0) + option := 1 + else + option := 2 + else if (variation.length == 3) + option := 3 + else if (variation.length == 6) + option := 4 + else throw Error("Invalid variation parameter.") + } + else + if not IsObject(variation) + if (variation == 0) + option := 5 + else + option := 6 + else if (variation.length == 3) + option := 7 + else throw Error("Invalid variation parameter.") + + ; ---------------------------- Machine code generated with MCode4GCC using gcc 13.2.0 ---------------------------- + + ; C source code - https://godbolt.org/z/n8894d9oG + pixelsearch := this.Base64Code((A_PtrSize == 4) + ? "VYnli1UMi00Qi0UIOdBzCTkIdAWDwATr813D" + : "SInISDnQcwtEOQB0BkiDwATr8MM=") + + ; C source code - https://godbolt.org/z/19TM9Gzo5 + pixelsearch2 := this.Base64Code((A_PtrSize == 4) ? "VYnlVlNRikUQilUcik0gil0ki3UIiEX3ikUUiEX2ikUYiEX1O3UMcyiKRgI4RfdyGzpF9nIWikYBOEX1cg440HIKigY4wXIEONhzBYPGBOvTWonwW15dww==" : "VlNEilQkOESKXCRAilwkSECKdCRQSInISDnQcyuKSAJBOMhyHUQ4yXIYikgBQTjKchBEONlyC4oIOMtyBUA48XMGSIPABOvQW17D") - ; Lift color to 32-bits if first 8 bits are zero. - (color >> 24) || color |= 0xFF000000 + ; C source code - https://godbolt.org/z/4hEhb7vG8 + pixelsearch3 := this.Base64Code((A_PtrSize == 4) + ? "VYnlU4tNDItFCDnIcxkx0jtVFHQNi10QixyTORh0CELr7oPABOvjW13D" + : "SInISDnQcxwxyUQ5yXMPSP/BRYtUiPxEORB17usGSIPABOvfww==") + + ; C source code - https://godbolt.org/z/oEGGeedac + pixelsearch4 := this.Base64Code((A_PtrSize == 4) + ? "VYnlV1ZTUYt1EIt9FItVCDtVDHNFikICiloBiEXzigKIRfIxwDtFGHQrik3zOEyGAnIfOkyHAnIZOFyGAXITOlyHAXINik3yOAyGcgU6DIdzCEDr0IPCBOu2idBaW15fXcM=" + : "U0iJyEg50HNFRIpQAkSKWAExyYoYO0wkMHMtRThUiAJyIUU6VIkCchpFOFyIAXITRTpciQFyDEE4HIhyBkE6HIlzC0j/wevNSIPABOu2W8M=") - ; PixelSearch, single color with no variation - if !IsObject(variation) && (variation == 0) - byte := DllCall(PixelSearch, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "cdecl ptr") + ; ---------------------------------------------------------------------------------------------------------------- - ; PixelSearch, single color with single variation - else if !IsObject(variation) && (variation != 0) { + if (option == 1) + ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. + byte := DllCall(pixelsearch, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "cdecl ptr") + + if (option == 2) { r := ((color & 0xFF0000) >> 16) g := ((color & 0xFF00) >> 8) b := ((color & 0xFF)) v := abs(variation) - ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. - byte := DllCall(PixelSearch2, "ptr", this.ptr, "ptr", this.ptr + this.size + byte := DllCall(pixelsearch2, "ptr", this.ptr, "ptr", this.ptr + this.size , "uchar", min(r+v, 255) , "uchar", max(r-v, 0) , "uchar", min(g+v, 255) @@ -2400,25 +2444,26 @@ class ImagePut { , "cdecl ptr") } - ; PixelSearch, single color with multiple variation. - else if IsObject(variation) && (variation.length == 3) { + if (option == 3) { r := ((color & 0xFF0000) >> 16) g := ((color & 0xFF00) >> 8) b := ((color & 0xFF)) - - byte := DllCall(PixelSearch2, "ptr", this.ptr, "ptr", this.ptr + this.size - , "uchar", min(r + variation[1], 255) - , "uchar", max(r - variation[1], 0) - , "uchar", min(g + variation[2], 255) - , "uchar", max(g - variation[2], 0) - , "uchar", min(b + variation[3], 255) - , "uchar", max(b - variation[3], 0) + vr := abs(variation[1]) + vg := abs(variation[2]) + vb := abs(variation[3]) + + byte := DllCall(pixelsearch2, "ptr", this.ptr, "ptr", this.ptr + this.size + , "uchar", min(r + vr, 255) + , "uchar", max(r - vr, 0) + , "uchar", min(g + vg, 255) + , "uchar", max(g - vg, 0) + , "uchar", min(b + vb, 255) + , "uchar", max(b - vb, 0) , "cdecl ptr") } - ; PixelSearch, range of colors. - else if IsObject(variation) && (variation.length == 6) { - byte := DllCall(PixelSearch2, "ptr", this.ptr, "ptr", this.ptr + this.size + if (option == 4) + byte := DllCall(pixelsearch2, "ptr", this.ptr, "ptr", this.ptr + this.size , "uchar", min(max(variation[1], variation[2]), 255) , "uchar", max(min(variation[1], variation[2]), 0) , "uchar", min(max(variation[3], variation[4]), 255) @@ -2426,9 +2471,71 @@ class ImagePut { , "uchar", min(max(variation[5], variation[6]), 255) , "uchar", max(min(variation[5], variation[6]), 0) , "cdecl ptr") + + if (option == 5) { + ; Create a struct of unsigned integers. + colors := Buffer(4*color.length) + + ; Fill the struct by iterating through the input array. + for c in color { + (c >> 24) || c |= 0xFF000000 ; Lift colors to 32-bit ARGB. + NumPut("uint", c, colors, 4*(A_Index-1)) ; Place the unsigned int at each offset. + } + + byte := DllCall(pixelsearch3, "ptr", this.ptr, "ptr", this.ptr + this.size, "ptr", colors, "uint", color.length, "cdecl ptr") + } + + ; Options 6 & 7 - Creates a high and low struct where each pair is the min and max range. + + if (option == 6) { + high := Buffer(4*color.length) + low := Buffer(4*color.length) + + for c in color { + A_Offset := A_Index - 1 + + r := ((c & 0xFF0000) >> 16) + g := ((c & 0xFF00) >> 8) + b := ((c & 0xFF)) + v := abs(variation) + + NumPut("uchar", min(r+v, 255), high, 4*A_Offset + 2) + NumPut("uchar", min(g+v, 255), high, 4*A_Offset + 1) + NumPut("uchar", min(b+v, 255), high, 4*A_Offset + 0) + + NumPut("uchar", max(r-v, 0), low, 4*A_Offset + 2) + NumPut("uchar", max(g-v, 0), low, 4*A_Offset + 1) + NumPut("uchar", max(b-v, 0), low, 4*A_Offset + 0) + } + + byte := DllCall(pixelsearch4, "ptr", this.ptr, "ptr", this.ptr + this.size, "ptr", high, "ptr", low, "uint", color.length, "cdecl ptr") } - else throw Error("Invalid variation parameter.") + if (option == 7) { + high := Buffer(4*color.length) + low := Buffer(4*color.length) + + for c in color { + A_Offset := A_Index - 1 + + r := ((c & 0xFF0000) >> 16) + g := ((c & 0xFF00) >> 8) + b := ((c & 0xFF)) + vr := abs(variation[1]) + vg := abs(variation[2]) + vb := abs(variation[3]) + + NumPut("uchar", min(r + vr, 255), high, 4*A_Offset + 2) + NumPut("uchar", min(g + vg, 255), high, 4*A_Offset + 1) + NumPut("uchar", min(b + vb, 255), high, 4*A_Offset + 0) + + NumPut("uchar", max(r - vr, 0), low, 4*A_Offset + 2) + NumPut("uchar", max(g - vg, 0), low, 4*A_Offset + 1) + NumPut("uchar", max(b - vb, 0), low, 4*A_Offset + 0) + } + + byte := DllCall(pixelsearch4, "ptr", this.ptr, "ptr", this.ptr + this.size, "ptr", high, "ptr", low, "uint", color.length, "cdecl ptr") + } ; Compare the address to the out-of-bounds limit. if (byte == this.ptr + this.size) @@ -2668,7 +2775,7 @@ class ImagePut { ; Set itself as the *internal* top level window. DllCall("SetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 0, "ptr", hwnd) - + ; A layered child window is only available on Windows 8+. hwnd_child := this.show(pBitmap, title, [0, 0, w, h], WS_CHILD | WS_VISIBLE, WS_EX_LAYERED, hwnd) @@ -2952,7 +3059,7 @@ class ImagePut { ; Exit loop. if !pBitmap return - + ; Get next frame. frames := NumGet(Item + 4, "uint") // 4 ; Max frames frame := wParam + 1 ; Next frame From 4c092fbae88206723a2638a775cf263a5ee52856 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 5 Sep 2023 00:02:40 -0400 Subject: [PATCH 418/492] reduce line length --- ImagePut (for v1).ahk | 4 ++-- ImagePut.ahk | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 9a36bf4c..d24e119d 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2400,7 +2400,7 @@ class ImagePut { option := 7 else throw Exception("Invalid variation parameter.") - ; ---------------------------- Machine code generated with MCode4GCC using gcc 13.2.0 ---------------------------- + ; ----------------------- Machine code generated with MCode4GCC using gcc 13.2.0 ----------------------- ; C source code - https://godbolt.org/z/n8894d9oG pixelsearch := this.Base64Code((A_PtrSize == 4) @@ -2422,7 +2422,7 @@ class ImagePut { ? "VYnlV1ZTUYt1EIt9FItVCDtVDHNFikICiloBiEXzigKIRfIxwDtFGHQrik3zOEyGAnIfOkyHAnIZOFyGAXITOlyHAXINik3yOAyGcgU6DIdzCEDr0IPCBOu2idBaW15fXcM=" : "U0iJyEg50HNFRIpQAkSKWAExyYoYO0wkMHMtRThUiAJyIUU6VIkCchpFOFyIAXITRTpciQFyDEE4HIhyBkE6HIlzC0j/wevNSIPABOu2W8M=") - ; ---------------------------------------------------------------------------------------------------------------- + ; ------------------------------------------------------------------------------------------------------ if (option == 1) ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. diff --git a/ImagePut.ahk b/ImagePut.ahk index 813bf440..f8af67c6 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2400,7 +2400,7 @@ class ImagePut { option := 7 else throw Error("Invalid variation parameter.") - ; ---------------------------- Machine code generated with MCode4GCC using gcc 13.2.0 ---------------------------- + ; ----------------------- Machine code generated with MCode4GCC using gcc 13.2.0 ----------------------- ; C source code - https://godbolt.org/z/n8894d9oG pixelsearch := this.Base64Code((A_PtrSize == 4) @@ -2422,7 +2422,7 @@ class ImagePut { ? "VYnlV1ZTUYt1EIt9FItVCDtVDHNFikICiloBiEXzigKIRfIxwDtFGHQrik3zOEyGAnIfOkyHAnIZOFyGAXITOlyHAXINik3yOAyGcgU6DIdzCEDr0IPCBOu2idBaW15fXcM=" : "U0iJyEg50HNFRIpQAkSKWAExyYoYO0wkMHMtRThUiAJyIUU6VIkCchpFOFyIAXITRTpciQFyDEE4HIhyBkE6HIlzC0j/wevNSIPABOu2W8M=") - ; ---------------------------------------------------------------------------------------------------------------- + ; ------------------------------------------------------------------------------------------------------ if (option == 1) ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. From d4cfcd955c0aa22289a718f8fe475233a5c56fcb Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 5 Sep 2023 19:25:21 -0400 Subject: [PATCH 419/492] C source files --- ImagePut (for v1).ahk | 4 ++-- ImagePut.ahk | 4 ++-- source/{imagesearch.c => imagesearch1.c} | 0 source/{pixelsearch.c => pixelsearch1.c} | 0 4 files changed, 4 insertions(+), 4 deletions(-) rename source/{imagesearch.c => imagesearch1.c} (100%) rename source/{pixelsearch.c => pixelsearch1.c} (100%) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index d24e119d..9a36bf4c 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2400,7 +2400,7 @@ class ImagePut { option := 7 else throw Exception("Invalid variation parameter.") - ; ----------------------- Machine code generated with MCode4GCC using gcc 13.2.0 ----------------------- + ; ---------------------------- Machine code generated with MCode4GCC using gcc 13.2.0 ---------------------------- ; C source code - https://godbolt.org/z/n8894d9oG pixelsearch := this.Base64Code((A_PtrSize == 4) @@ -2422,7 +2422,7 @@ class ImagePut { ? "VYnlV1ZTUYt1EIt9FItVCDtVDHNFikICiloBiEXzigKIRfIxwDtFGHQrik3zOEyGAnIfOkyHAnIZOFyGAXITOlyHAXINik3yOAyGcgU6DIdzCEDr0IPCBOu2idBaW15fXcM=" : "U0iJyEg50HNFRIpQAkSKWAExyYoYO0wkMHMtRThUiAJyIUU6VIkCchpFOFyIAXITRTpciQFyDEE4HIhyBkE6HIlzC0j/wevNSIPABOu2W8M=") - ; ------------------------------------------------------------------------------------------------------ + ; ---------------------------------------------------------------------------------------------------------------- if (option == 1) ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. diff --git a/ImagePut.ahk b/ImagePut.ahk index f8af67c6..813bf440 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2400,7 +2400,7 @@ class ImagePut { option := 7 else throw Error("Invalid variation parameter.") - ; ----------------------- Machine code generated with MCode4GCC using gcc 13.2.0 ----------------------- + ; ---------------------------- Machine code generated with MCode4GCC using gcc 13.2.0 ---------------------------- ; C source code - https://godbolt.org/z/n8894d9oG pixelsearch := this.Base64Code((A_PtrSize == 4) @@ -2422,7 +2422,7 @@ class ImagePut { ? "VYnlV1ZTUYt1EIt9FItVCDtVDHNFikICiloBiEXzigKIRfIxwDtFGHQrik3zOEyGAnIfOkyHAnIZOFyGAXITOlyHAXINik3yOAyGcgU6DIdzCEDr0IPCBOu2idBaW15fXcM=" : "U0iJyEg50HNFRIpQAkSKWAExyYoYO0wkMHMtRThUiAJyIUU6VIkCchpFOFyIAXITRTpciQFyDEE4HIhyBkE6HIlzC0j/wevNSIPABOu2W8M=") - ; ------------------------------------------------------------------------------------------------------ + ; ---------------------------------------------------------------------------------------------------------------- if (option == 1) ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. diff --git a/source/imagesearch.c b/source/imagesearch1.c similarity index 100% rename from source/imagesearch.c rename to source/imagesearch1.c diff --git a/source/pixelsearch.c b/source/pixelsearch1.c similarity index 100% rename from source/pixelsearch.c rename to source/pixelsearch1.c From 698490b67cdc847984fdc2ff139d6a6f716a1483 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 5 Sep 2023 19:27:10 -0400 Subject: [PATCH 420/492] C source files --- source/pixelsearch1x.c | 36 ++++++++++++++++++++++++++++++++++++ source/pixelsearch1y.c | 36 ++++++++++++++++++++++++++++++++++++ source/pixelsearch3.c | 9 +++++++++ source/pixelsearch4.c | 24 ++++++++++++++++++++++++ source/some_other.c | 14 -------------- source/some_xmm_tests.c | 11 ----------- 6 files changed, 105 insertions(+), 25 deletions(-) create mode 100644 source/pixelsearch1x.c create mode 100644 source/pixelsearch1y.c create mode 100644 source/pixelsearch3.c create mode 100644 source/pixelsearch4.c delete mode 100644 source/some_other.c delete mode 100644 source/some_xmm_tests.c diff --git a/source/pixelsearch1x.c b/source/pixelsearch1x.c new file mode 100644 index 00000000..141bcc7e --- /dev/null +++ b/source/pixelsearch1x.c @@ -0,0 +1,36 @@ +#include + +unsigned int * pixelsearch1(unsigned int * start, unsigned int * end, unsigned int color) { + + // Create a vector of four copies of color. + __m128i vcolor = _mm_set1_epi32(color); + + // Loop over start pointer with a step of four unsigned integers. + while (start < end - 3) { + + // Load four unsigned integers from start into a vector. + __m128i vstart = _mm_loadu_si128((__m128i *) start); + + // Compare vstart and vcolor for equality. + __m128i vcmp = _mm_cmpeq_epi32(vstart, vcolor); + + // Create a mask from each byte (using the most significant bit) in vcmp. + int mask = _mm_movemask_epi8(vcmp); + + // If the mask is nonzero, there is at least one match. + if (mask != 0) + break; + + // Increment start by four unsigned integers. + start += 4; + } + + // Clean up any remaining elements. + while (start < end) { + if (*start == color) + return start; + start++; + } + + return start; // start == end if no match. +} \ No newline at end of file diff --git a/source/pixelsearch1y.c b/source/pixelsearch1y.c new file mode 100644 index 00000000..236ea8f0 --- /dev/null +++ b/source/pixelsearch1y.c @@ -0,0 +1,36 @@ +#include + +unsigned int * pixelsearch1(unsigned int * start, unsigned int * end, unsigned int color) { + + // Create a vector of eight copies of color. + __m256i vcolor = _mm256_set1_epi32(color); + + // Loop over start pointer with a step of eight unsigned integers. + while (start < end - 7) { + + // Load eight unsigned integers from start into a vector. + __m256i vstart = _mm256_loadu_si256((__m256i *) start); + + // Compare vstart and vcolor for equality. + __m256i vcmp = _mm256_cmpeq_epi32(vstart, vcolor); + + // Create a mask from each byte (using the most significant bit) in vcmp. + int mask = _mm256_movemask_epi8(vcmp); + + // If the mask is nonzero, there is at least one match. + if (mask != 0) + break; + + // Increment start by eight unsigned integers. + start += 8; + } + + // Clean up any remaining elements. + while (start < end) { + if (*start == color) + return start; + start++; + } + + return start; // start == end if no match. +} \ No newline at end of file diff --git a/source/pixelsearch3.c b/source/pixelsearch3.c new file mode 100644 index 00000000..e5cb9728 --- /dev/null +++ b/source/pixelsearch3.c @@ -0,0 +1,9 @@ +unsigned int * pixelsearch3(unsigned int * start, unsigned int * end, unsigned int * colors, unsigned int length) { + while (start < end) { + for (int i = 0; i < length; i++) + if (*start == colors[i]) + return start; + start++; + } + return start; // start == end if no match. +} \ No newline at end of file diff --git a/source/pixelsearch4.c b/source/pixelsearch4.c new file mode 100644 index 00000000..37b83e5b --- /dev/null +++ b/source/pixelsearch4.c @@ -0,0 +1,24 @@ +unsigned int * pixelsearch4(unsigned int * start, unsigned int * end, unsigned int * high, unsigned int * low, unsigned int length) { + unsigned char r, g, b, rh, gh, bh, rl, gl, bl; + while (start < end) { + + r = *((unsigned char *) start + 2); + g = *((unsigned char *) start + 1); + b = *((unsigned char *) start + 0); + + for (int i = 0; i < length; i++) { + + rh = *((unsigned char *) high + 4*i + 2); + gh = *((unsigned char *) high + 4*i + 1); + bh = *((unsigned char *) high + 4*i + 0); + rl = *((unsigned char *) low + 4*i + 2); + gl = *((unsigned char *) low + 4*i + 1); + bl = *((unsigned char *) low + 4*i + 0); + + if (rh >= r && r >= rl && gh >= g && g >= gl && bh >= b && b >= bl) + return start; + } + start++; + } + return start; // start == end if no match. +} \ No newline at end of file diff --git a/source/some_other.c b/source/some_other.c deleted file mode 100644 index e3109508..00000000 --- a/source/some_other.c +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include -#include -#include - -void main() { - int32_t __attribute__ ((aligned(16))) vector1[4] = { 1, 2, 3, 4 }; - int32_t __attribute__ ((aligned(16))) vector2[4] = { 1, 2, 2, 2 }; - int32_t __attribute__ ((aligned(16))) result[4]; - - __m128i v1 = _mm_load_si128((__m128i *)vector1); - __m128i v2 = _mm_load_si128((__m128i *)vector2); - __m128i vcmp = _mm_cmpeq_epi32(v1, v2); -} \ No newline at end of file diff --git a/source/some_xmm_tests.c b/source/some_xmm_tests.c deleted file mode 100644 index ddff9fbd..00000000 --- a/source/some_xmm_tests.c +++ /dev/null @@ -1,11 +0,0 @@ -#include -#include -#include - -int main(unsigned int * start) { - __m128i input = _mm_loadu_si128(*start); - const __m128i populated_0th_byte = _mm_shuffle_epi8(input, _mm_setzero_si128()); - const __m128i eq = _mm_cmpeq_epi8(input, populated_0th_byte); - - return (_mm_movemask_epi8(eq) == 0xffff); -} \ No newline at end of file From 1b9c9cad70aac2da7ec1a0e879995c6b7da14abc Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 5 Sep 2023 19:29:32 -0400 Subject: [PATCH 421/492] reduce line length again --- ImagePut (for v1).ahk | 4 ++-- ImagePut.ahk | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 9a36bf4c..d24e119d 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2400,7 +2400,7 @@ class ImagePut { option := 7 else throw Exception("Invalid variation parameter.") - ; ---------------------------- Machine code generated with MCode4GCC using gcc 13.2.0 ---------------------------- + ; ----------------------- Machine code generated with MCode4GCC using gcc 13.2.0 ----------------------- ; C source code - https://godbolt.org/z/n8894d9oG pixelsearch := this.Base64Code((A_PtrSize == 4) @@ -2422,7 +2422,7 @@ class ImagePut { ? "VYnlV1ZTUYt1EIt9FItVCDtVDHNFikICiloBiEXzigKIRfIxwDtFGHQrik3zOEyGAnIfOkyHAnIZOFyGAXITOlyHAXINik3yOAyGcgU6DIdzCEDr0IPCBOu2idBaW15fXcM=" : "U0iJyEg50HNFRIpQAkSKWAExyYoYO0wkMHMtRThUiAJyIUU6VIkCchpFOFyIAXITRTpciQFyDEE4HIhyBkE6HIlzC0j/wevNSIPABOu2W8M=") - ; ---------------------------------------------------------------------------------------------------------------- + ; ------------------------------------------------------------------------------------------------------ if (option == 1) ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. diff --git a/ImagePut.ahk b/ImagePut.ahk index 813bf440..f8af67c6 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2400,7 +2400,7 @@ class ImagePut { option := 7 else throw Error("Invalid variation parameter.") - ; ---------------------------- Machine code generated with MCode4GCC using gcc 13.2.0 ---------------------------- + ; ----------------------- Machine code generated with MCode4GCC using gcc 13.2.0 ----------------------- ; C source code - https://godbolt.org/z/n8894d9oG pixelsearch := this.Base64Code((A_PtrSize == 4) @@ -2422,7 +2422,7 @@ class ImagePut { ? "VYnlV1ZTUYt1EIt9FItVCDtVDHNFikICiloBiEXzigKIRfIxwDtFGHQrik3zOEyGAnIfOkyHAnIZOFyGAXITOlyHAXINik3yOAyGcgU6DIdzCEDr0IPCBOu2idBaW15fXcM=" : "U0iJyEg50HNFRIpQAkSKWAExyYoYO0wkMHMtRThUiAJyIUU6VIkCchpFOFyIAXITRTpciQFyDEE4HIhyBkE6HIlzC0j/wevNSIPABOu2W8M=") - ; ---------------------------------------------------------------------------------------------------------------- + ; ------------------------------------------------------------------------------------------------------ if (option == 1) ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. From 1f982f9c83b4ea0d3737402e0f08065ffc152e16 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 5 Sep 2023 20:58:35 -0400 Subject: [PATCH 422/492] Use SSE2 to increase pixelsearch1 by 100% - 300% --- ImagePut.ahk | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index f8af67c6..3cfb8a55 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2402,10 +2402,10 @@ class ImagePut { ; ----------------------- Machine code generated with MCode4GCC using gcc 13.2.0 ----------------------- - ; C source code - https://godbolt.org/z/n8894d9oG - pixelsearch := this.Base64Code((A_PtrSize == 4) - ? "VYnli1UMi00Qi0UIOdBzCTkIdAWDwATr813D" - : "SInISDnQcwtEOQB0BkiDwATr8MM=") + ; C source code - https://godbolt.org/z/6jPnc6b5s + pixelsearch1 := this.Base64Code((A_PtrSize == 4) + ? "VYnlVotNEItVDFOLRQhmD27RjVr0Zg9wygA52HMbDxAAZg92wWYP1/CF9nUMg8AQ6+g5CHQHg8AEOdBy9VteXcM=" + : "ZkEPbtBIichIjUr0Zg9wygBIOchzIA8QAGYPdsFmRA/XyEWFyXUPSIPAEOvkRDkAdAlIg8AESDnQcvLD") ; C source code - https://godbolt.org/z/19TM9Gzo5 pixelsearch2 := this.Base64Code((A_PtrSize == 4) @@ -2426,7 +2426,7 @@ class ImagePut { if (option == 1) ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. - byte := DllCall(pixelsearch, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "cdecl ptr") + byte := DllCall(pixelsearch1, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "cdecl ptr") if (option == 2) { r := ((color & 0xFF0000) >> 16) From 0127f32550d34d60903592d2f0beb7c63cf89f7c Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 5 Sep 2023 21:01:19 -0400 Subject: [PATCH 423/492] Use SSE2 to increase pixelsearch1 by 100% - 300% --- ImagePut (for v1).ahk | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index d24e119d..b0447e0b 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2402,10 +2402,10 @@ class ImagePut { ; ----------------------- Machine code generated with MCode4GCC using gcc 13.2.0 ----------------------- - ; C source code - https://godbolt.org/z/n8894d9oG - pixelsearch := this.Base64Code((A_PtrSize == 4) - ? "VYnli1UMi00Qi0UIOdBzCTkIdAWDwATr813D" - : "SInISDnQcwtEOQB0BkiDwATr8MM=") + ; C source code - https://godbolt.org/z/6jPnc6b5s + pixelsearch1 := this.Base64Code((A_PtrSize == 4) + ? "VYnlVotNEItVDFOLRQhmD27RjVr0Zg9wygA52HMbDxAAZg92wWYP1/CF9nUMg8AQ6+g5CHQHg8AEOdBy9VteXcM=" + : "ZkEPbtBIichIjUr0Zg9wygBIOchzIA8QAGYPdsFmRA/XyEWFyXUPSIPAEOvkRDkAdAlIg8AESDnQcvLD") ; C source code - https://godbolt.org/z/19TM9Gzo5 pixelsearch2 := this.Base64Code((A_PtrSize == 4) @@ -2426,7 +2426,7 @@ class ImagePut { if (option == 1) ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. - byte := DllCall(pixelsearch, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "cdecl ptr") + byte := DllCall(pixelsearch1, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "cdecl ptr") if (option == 2) { r := ((color & 0xFF0000) >> 16) From df47d96be7f0955fcba3a7411577313be4d75cc4 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 5 Sep 2023 23:15:41 -0400 Subject: [PATCH 424/492] Use SSE2 to increase pixelsearch2 by 50% - 100% --- ImagePut (for v1).ahk | 10 +++++++--- ImagePut.ahk | 10 +++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index b0447e0b..ee2548a5 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2407,10 +2407,14 @@ class ImagePut { ? "VYnlVotNEItVDFOLRQhmD27RjVr0Zg9wygA52HMbDxAAZg92wWYP1/CF9nUMg8AQ6+g5CHQHg8AEOdBy9VteXcM=" : "ZkEPbtBIichIjUr0Zg9wygBIOchzIA8QAGYPdsFmRA/XyEWFyXUPSIPAEOvkRDkAdAlIg8AESDnQcvLD") - ; C source code - https://godbolt.org/z/19TM9Gzo5 + ; C source code - https://godbolt.org/z/YcW7bE6YK pixelsearch2 := this.Base64Code((A_PtrSize == 4) - ? "VYnlVlNRikUQilUcik0gil0ki3UIiEX3ikUUiEX2ikUYiEX1O3UMcyiKRgI4RfdyGzpF9nIWikYBOEX1cg440HIKigY4wXIEONhzBYPGBOvTWonwW15dww==" - : "VlNEilQkOESKXCRAilwkSECKdCRQSInISDnQcyuKSAJBOMhyHUQ4yXIYikgBQTjKchBEONlyC4oIOMtyBUA48XMGSIPABOvQW17D") + ? "VQ9X0onlV1ZTg+Twg+wQi0UQi00Yi3UgilUUil0ci30MiEQkDw+2wIhMJA0tAAAAAYPBENPgjU4IiFQkDopVJNPgiFwkDI1P9Inz" + . "Zg9u4ItFCGYPcMQAOchzLQ8QCA8QKA8o2mYPZMhmD2TdD1bLZg/X8YX2dRGDwBDr24pIAjhMJA9zCYPABDn4cvDrHzpMJA5y8YpI" + . "AThMJA1y6DpMJAxy4ooIOMty3DjRctiNZfRbXl9dww==" + : "VVdWUw9X24tsJFiKXCRQQIp8JGCJ7kiJyItMJEhFicJFD7bAQYHoAAAAAUGJy4PBEEHT4I1NCEHT4EiNSvRmQQ9u6GYPcMUASDnI" + . "czAPEBAPKOMPKMpmD2TiZg9kyA9WzGZED9fBRYXAdRJIg8AQ69eKSAJBOMpzC0iDwARIOdBy7+sdRDjJcvCKSAFBOMty6DjZcuSK" + . "CEA4znLdQDj5cthbXl9dww==") ; C source code - https://godbolt.org/z/4hEhb7vG8 pixelsearch3 := this.Base64Code((A_PtrSize == 4) diff --git a/ImagePut.ahk b/ImagePut.ahk index 3cfb8a55..305be8c9 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2407,10 +2407,14 @@ class ImagePut { ? "VYnlVotNEItVDFOLRQhmD27RjVr0Zg9wygA52HMbDxAAZg92wWYP1/CF9nUMg8AQ6+g5CHQHg8AEOdBy9VteXcM=" : "ZkEPbtBIichIjUr0Zg9wygBIOchzIA8QAGYPdsFmRA/XyEWFyXUPSIPAEOvkRDkAdAlIg8AESDnQcvLD") - ; C source code - https://godbolt.org/z/19TM9Gzo5 + ; C source code - https://godbolt.org/z/YcW7bE6YK pixelsearch2 := this.Base64Code((A_PtrSize == 4) - ? "VYnlVlNRikUQilUcik0gil0ki3UIiEX3ikUUiEX2ikUYiEX1O3UMcyiKRgI4RfdyGzpF9nIWikYBOEX1cg440HIKigY4wXIEONhzBYPGBOvTWonwW15dww==" - : "VlNEilQkOESKXCRAilwkSECKdCRQSInISDnQcyuKSAJBOMhyHUQ4yXIYikgBQTjKchBEONlyC4oIOMtyBUA48XMGSIPABOvQW17D") + ? "VQ9X0onlV1ZTg+Twg+wQi0UQi00Yi3UgilUUil0ci30MiEQkDw+2wIhMJA0tAAAAAYPBENPgjU4IiFQkDopVJNPgiFwkDI1P9Inz" + . "Zg9u4ItFCGYPcMQAOchzLQ8QCA8QKA8o2mYPZMhmD2TdD1bLZg/X8YX2dRGDwBDr24pIAjhMJA9zCYPABDn4cvDrHzpMJA5y8YpI" + . "AThMJA1y6DpMJAxy4ooIOMty3DjRctiNZfRbXl9dww==" + : "VVdWUw9X24tsJFiKXCRQQIp8JGCJ7kiJyItMJEhFicJFD7bAQYHoAAAAAUGJy4PBEEHT4I1NCEHT4EiNSvRmQQ9u6GYPcMUASDnI" + . "czAPEBAPKOMPKMpmD2TiZg9kyA9WzGZED9fBRYXAdRJIg8AQ69eKSAJBOMpzC0iDwARIOdBy7+sdRDjJcvCKSAFBOMty6DjZcuSK" + . "CEA4znLdQDj5cthbXl9dww==") ; C source code - https://godbolt.org/z/4hEhb7vG8 pixelsearch3 := this.Base64Code((A_PtrSize == 4) From 66dfa671ea851376e29bae65fa4a32f953fa016d Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 5 Sep 2023 23:21:33 -0400 Subject: [PATCH 425/492] C source files --- source/imagesearch1.c | 2 +- .../{imagesearchall.c => imagesearchall1.c} | 2 +- source/pixelsearch1.c | 2 +- source/pixelsearch2x.c | 48 +++++++++++++++++++ .../{pixelsearchall.c => pixelsearchall1.c} | 2 +- 5 files changed, 52 insertions(+), 4 deletions(-) rename source/{imagesearchall.c => imagesearchall1.c} (88%) create mode 100644 source/pixelsearch2x.c rename source/{pixelsearchall.c => pixelsearchall1.c} (60%) diff --git a/source/imagesearch1.c b/source/imagesearch1.c index dcaffca1..d2a628cc 100644 --- a/source/imagesearch1.c +++ b/source/imagesearch1.c @@ -1,4 +1,4 @@ -unsigned int * imagesearch(unsigned int * start, unsigned int width, unsigned int height, unsigned int * s, unsigned int w, unsigned int h) { +unsigned int * imagesearch1(unsigned int * start, unsigned int width, unsigned int height, unsigned int * s, unsigned int w, unsigned int h) { // width, height, start, current, end refer to the haystack (main image) // x, y, w, h, s, c, e refer to the needle (search image) diff --git a/source/imagesearchall.c b/source/imagesearchall1.c similarity index 88% rename from source/imagesearchall.c rename to source/imagesearchall1.c index 68d3869b..fb8c775a 100644 --- a/source/imagesearchall.c +++ b/source/imagesearchall1.c @@ -1,4 +1,4 @@ -unsigned int imagesearchall(unsigned int ** result, unsigned int capacity, unsigned int * start, unsigned int width, unsigned int height, unsigned int * s, unsigned int w, unsigned int h) { +unsigned int imagesearchall1(unsigned int ** result, unsigned int capacity, unsigned int * start, unsigned int width, unsigned int height, unsigned int * s, unsigned int w, unsigned int h) { // width, height, start, current, end refer to the haystack (main image) // x, y, w, h, s, c, e refer to the needle (search image) unsigned int count = 0; diff --git a/source/pixelsearch1.c b/source/pixelsearch1.c index c95d2ad6..9439a72d 100644 --- a/source/pixelsearch1.c +++ b/source/pixelsearch1.c @@ -1,4 +1,4 @@ -unsigned int * pixelsearch(unsigned int * start, unsigned int * end, unsigned int color) { +unsigned int * pixelsearch1(unsigned int * start, unsigned int * end, unsigned int color) { while (start < end) { if (*start == color) return start; diff --git a/source/pixelsearch2x.c b/source/pixelsearch2x.c new file mode 100644 index 00000000..07e82b86 --- /dev/null +++ b/source/pixelsearch2x.c @@ -0,0 +1,48 @@ +#include + +unsigned int * pixelsearch2(unsigned int * start, unsigned int * end, unsigned char rh, unsigned char rl, unsigned char gh, unsigned char gl, unsigned char bh, unsigned char bl) { + + // Don't as me why the following 00 << 24 compresses so well. + unsigned int h = 0xFF000000 + rh << 16 + gh << 8 + bh << 0; + unsigned int l = 0x00 << 24 + rl << 16 + gl << 8 + bl << 0; + + __m128i vh = _mm_set1_epi32(h); + __m128i vl = _mm_set1_epi32(l); + + while (start < end - 3) { + + __m128i vstart = _mm_loadu_si128((__m128i *) start); + + // Note that boolean logic was used to simplify the code below. + // <= and >= can be defined as < or = and > or = + // Reversing <= makes it become not >. + // (not >) and (not <) + // DeMorgan's Rule + // > or < + + __m128i v2 = _mm_cmpgt_epi8(vstart, vh); + __m128i v3 = _mm_cmplt_epi8(vstart, vl); + + __m128i v1234 = _mm_or_si128(v2, v3); + + int mask = _mm_movemask_epi8(v1234); + + if (mask != 0) + break; + + start += 4; + } + + // Clean up any remaining elements. + unsigned char r, g, b; + while (start < end) { + r = *((unsigned char *) start + 2); + g = *((unsigned char *) start + 1); + b = *((unsigned char *) start + 0); + if (rh >= r && r >= rl && gh >= g && g >= gl && bh >= b && b >= bl) + return start; + start++; + } + + return start; // start == end if no match. +} \ No newline at end of file diff --git a/source/pixelsearchall.c b/source/pixelsearchall1.c similarity index 60% rename from source/pixelsearchall.c rename to source/pixelsearchall1.c index ea100f9c..bc555528 100644 --- a/source/pixelsearchall.c +++ b/source/pixelsearchall1.c @@ -1,4 +1,4 @@ -unsigned int pixelsearchall(unsigned int ** result, unsigned int capacity, unsigned int * start, unsigned int * end, unsigned int color) { +unsigned int pixelsearchall1(unsigned int ** result, unsigned int capacity, unsigned int * start, unsigned int * end, unsigned int color) { unsigned int count = 0; while (start < end) { if (*start == color) { From 490748b135a3969c0520fa6bbc39d45587d5aac1 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 6 Sep 2023 21:07:10 -0400 Subject: [PATCH 426/492] C source files --- source/pixelsearch2x.c | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/source/pixelsearch2x.c b/source/pixelsearch2x.c index 07e82b86..8af498d2 100644 --- a/source/pixelsearch2x.c +++ b/source/pixelsearch2x.c @@ -1,38 +1,45 @@ #include +#define _mm_cmpge_epu8(a, b) _mm_cmpeq_epi8(_mm_max_epu8(a, b), a) +#define _mm_cmple_epu8(a, b) _mm_cmpge_epu8(b, a) +#define _mm_cmpgt_epu8(a, b) _mm_xor_si128(_mm_cmple_epu8(a, b), _mm_set1_epi8(-1)) +#define _mm_cmplt_epu8(a, b) _mm_cmpgt_epu8(b, a) + unsigned int * pixelsearch2(unsigned int * start, unsigned int * end, unsigned char rh, unsigned char rl, unsigned char gh, unsigned char gl, unsigned char bh, unsigned char bl) { - // Don't as me why the following 00 << 24 compresses so well. - unsigned int h = 0xFF000000 + rh << 16 + gh << 8 + bh << 0; - unsigned int l = 0x00 << 24 + rl << 16 + gl << 8 + bl << 0; + // Reconstruct ARGB from individual color channels. + unsigned int h = (0xFF << 24 | rh << 16 | gh << 8 | bh << 0); + unsigned int l = (0x00 << 24 | rl << 16 | gl << 8 | bl << 0); + // Create a vector of four copies. __m128i vh = _mm_set1_epi32(h); __m128i vl = _mm_set1_epi32(l); + __m128i vmask = _mm_set1_epi32(0xFFFFFFFF); + // Loop over start pointer with a step of four unsigned integers. while (start < end - 3) { + // Load four unsigned integers from start into a vector. __m128i vstart = _mm_loadu_si128((__m128i *) start); - // Note that boolean logic was used to simplify the code below. - // <= and >= can be defined as < or = and > or = - // Reversing <= makes it become not >. - // (not >) and (not <) - // DeMorgan's Rule - // > or < - - __m128i v2 = _mm_cmpgt_epi8(vstart, vh); - __m128i v3 = _mm_cmplt_epi8(vstart, vl); + // Compare vstart <= vh and vstart >= vl. Note these are macros. + __m128i v2 = _mm_cmple_epu8(vstart, vh); + __m128i v3 = _mm_cmpge_epu8(vstart, vl); + __m128i v1234 = _mm_and_si128(v2, v3); + + // Compare equality to four unsigned integers. + __m128i vcmp = _mm_cmpeq_epi32(v1234, vmask); - __m128i v1234 = _mm_or_si128(v2, v3); - - int mask = _mm_movemask_epi8(v1234); + // Create a mask from each byte (using the most significant bit) in vcmp. + int mask = _mm_movemask_epi8(vcmp); + // If the mask is nonzero, there is at least one match. if (mask != 0) break; start += 4; } - + // Clean up any remaining elements. unsigned char r, g, b; while (start < end) { From 44343e1f606d41c53eadcc251920229798511a0f Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 6 Sep 2023 21:15:08 -0400 Subject: [PATCH 427/492] Fix pixelsearch2 to properly use SSE2 (100-200% speedup) --- ImagePut (for v1).ahk | 16 +++++++++------- ImagePut.ahk | 16 +++++++++------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index ee2548a5..9a919b3b 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2407,14 +2407,16 @@ class ImagePut { ? "VYnlVotNEItVDFOLRQhmD27RjVr0Zg9wygA52HMbDxAAZg92wWYP1/CF9nUMg8AQ6+g5CHQHg8AEOdBy9VteXcM=" : "ZkEPbtBIichIjUr0Zg9wygBIOchzIA8QAGYPdsFmRA/XyEWFyXUPSIPAEOvkRDkAdAlIg8AESDnQcvLD") - ; C source code - https://godbolt.org/z/YcW7bE6YK + ; C source code - https://godbolt.org/z/7fv3P6KTb pixelsearch2 := this.Base64Code((A_PtrSize == 4) - ? "VQ9X0onlV1ZTg+Twg+wQi0UQi00Yi3UgilUUil0ci30MiEQkDw+2wIhMJA0tAAAAAYPBENPgjU4IiFQkDopVJNPgiFwkDI1P9Inz" - . "Zg9u4ItFCGYPcMQAOchzLQ8QCA8QKA8o2mYPZMhmD2TdD1bLZg/X8YX2dRGDwBDr24pIAjhMJA9zCYPABDn4cvDrHzpMJA5y8YpI" - . "AThMJA1y6DpMJAxy4ooIOMty3DjRctiNZfRbXl9dww==" - : "VVdWUw9X24tsJFiKXCRQQIp8JGCJ7kiJyItMJEhFicJFD7bAQYHoAAAAAUGJy4PBEEHT4I1NCEHT4EiNSvRmQQ9u6GYPcMUASDnI" - . "czAPEBAPKOMPKMpmD2TiZg9kyA9WzGZED9fBRYXAdRJIg8AQ69eKSAJBOMpzC0iDwARIOdBy7+sdRDjJcvCKSAFBOMty6DjZcuSK" - . "CEA4znLdQDj5cthbXl9dww==") + ? "VWYPduSJ5VdWU4Pk8IPsEIpFFItdEItNGItVHIt1DIt9IIhEJA6KRSSIXCQPD7bbiEwkDcHjEA+2yYhEJAsPtkUgweEIiFQkDA+2" + . "0gnYweIICcgPtk0kDQAAAP8J0Q+2VRRmD27oi0UIZg9wzQDB4hAJ0Y1W9GYPbvFmD3DWADnQczkPEAAPEBgPEDhmD97BZg/e2mYP" + . "dMFmD3TfD1TDZg92xGYP18iFyXURg8AQ68+KUAI4VCQPcwmDwAQ58HLw6yM6VCQOcvGKUAE4VCQNcug6VCQMcuKKEIn5ONFy2jpU" + . "JAty1I1l9FteX13D" + : "QVZBVUFUVVdWU0SLbCRgi0QkaESLdCRwRItUJHhEie6Jx0UPtu0PtsBBweUIRIn1RQ+29kWJ1EWJw0UPtsBEicvB4AhBweAQRQ+2" + . "0kUPtslFCfBECdBBweEQRQnoRAnIQYHIAAAA/2YPbuhIichmQQ9uyEiNSvRmD3DBAGYPcM0AZg927Ug5yHM8DxAgDyjQDyjcZg/e" + . "1GYP3tlmD3TQZg903A9U02YPdtVmRA/XwkWFwHUSSIPAEOvLikgCQTjLcwtIg8AESDnQcu/rHTjZcvGKSAFAOM5y6UA4+XLkighA" + . "OM1y3UQ44XLYW15fXUFcQV1BXsM=") ; C source code - https://godbolt.org/z/4hEhb7vG8 pixelsearch3 := this.Base64Code((A_PtrSize == 4) diff --git a/ImagePut.ahk b/ImagePut.ahk index 305be8c9..0e4dd5c1 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2407,14 +2407,16 @@ class ImagePut { ? "VYnlVotNEItVDFOLRQhmD27RjVr0Zg9wygA52HMbDxAAZg92wWYP1/CF9nUMg8AQ6+g5CHQHg8AEOdBy9VteXcM=" : "ZkEPbtBIichIjUr0Zg9wygBIOchzIA8QAGYPdsFmRA/XyEWFyXUPSIPAEOvkRDkAdAlIg8AESDnQcvLD") - ; C source code - https://godbolt.org/z/YcW7bE6YK + ; C source code - https://godbolt.org/z/7fv3P6KTb pixelsearch2 := this.Base64Code((A_PtrSize == 4) - ? "VQ9X0onlV1ZTg+Twg+wQi0UQi00Yi3UgilUUil0ci30MiEQkDw+2wIhMJA0tAAAAAYPBENPgjU4IiFQkDopVJNPgiFwkDI1P9Inz" - . "Zg9u4ItFCGYPcMQAOchzLQ8QCA8QKA8o2mYPZMhmD2TdD1bLZg/X8YX2dRGDwBDr24pIAjhMJA9zCYPABDn4cvDrHzpMJA5y8YpI" - . "AThMJA1y6DpMJAxy4ooIOMty3DjRctiNZfRbXl9dww==" - : "VVdWUw9X24tsJFiKXCRQQIp8JGCJ7kiJyItMJEhFicJFD7bAQYHoAAAAAUGJy4PBEEHT4I1NCEHT4EiNSvRmQQ9u6GYPcMUASDnI" - . "czAPEBAPKOMPKMpmD2TiZg9kyA9WzGZED9fBRYXAdRJIg8AQ69eKSAJBOMpzC0iDwARIOdBy7+sdRDjJcvCKSAFBOMty6DjZcuSK" - . "CEA4znLdQDj5cthbXl9dww==") + ? "VWYPduSJ5VdWU4Pk8IPsEIpFFItdEItNGItVHIt1DIt9IIhEJA6KRSSIXCQPD7bbiEwkDcHjEA+2yYhEJAsPtkUgweEIiFQkDA+2" + . "0gnYweIICcgPtk0kDQAAAP8J0Q+2VRRmD27oi0UIZg9wzQDB4hAJ0Y1W9GYPbvFmD3DWADnQczkPEAAPEBgPEDhmD97BZg/e2mYP" + . "dMFmD3TfD1TDZg92xGYP18iFyXURg8AQ68+KUAI4VCQPcwmDwAQ58HLw6yM6VCQOcvGKUAE4VCQNcug6VCQMcuKKEIn5ONFy2jpU" + . "JAty1I1l9FteX13D" + : "QVZBVUFUVVdWU0SLbCRgi0QkaESLdCRwRItUJHhEie6Jx0UPtu0PtsBBweUIRIn1RQ+29kWJ1EWJw0UPtsBEicvB4AhBweAQRQ+2" + . "0kUPtslFCfBECdBBweEQRQnoRAnIQYHIAAAA/2YPbuhIichmQQ9uyEiNSvRmD3DBAGYPcM0AZg927Ug5yHM8DxAgDyjQDyjcZg/e" + . "1GYP3tlmD3TQZg903A9U02YPdtVmRA/XwkWFwHUSSIPAEOvLikgCQTjLcwtIg8AESDnQcu/rHTjZcvGKSAFAOM5y6UA4+XLkighA" + . "OM1y3UQ44XLYW15fXUFcQV1BXsM=") ; C source code - https://godbolt.org/z/4hEhb7vG8 pixelsearch3 := this.Base64Code((A_PtrSize == 4) From 6e38074d118e89a2e1f96bd5100e6dcfd8e08947 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 7 Sep 2023 23:23:46 -0400 Subject: [PATCH 428/492] Use SSE2 to improve pixelsearch3 (200% speedup) --- ImagePut (for v1).ahk | 14 +++++++++++--- ImagePut.ahk | 14 +++++++++++--- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 9a919b3b..4c278225 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2418,10 +2418,18 @@ class ImagePut { . "1GYP3tlmD3TQZg903A9U02YPdtVmRA/XwkWFwHUSSIPAEOvLikgCQTjLcwtIg8AESDnQcu/rHTjZcvGKSAFAOM5y6UA4+XLkighA" . "OM1y3UQ44XLYW15fXUFcQV1BXsM=") - ; C source code - https://godbolt.org/z/4hEhb7vG8 + ; C source code - https://godbolt.org/z/veshd46qn pixelsearch3 := this.Base64Code((A_PtrSize == 4) - ? "VYnlU4tNDItFCDnIcxkx0jtVFHQNi10QixyTORh0CELr7oPABOvjW13D" - : "SInISDnQcxwxyUQ5yXMPSP/BRYtUiPxEORB17usGSIPABOvfww==") + ? "VTHSieVXVlOD5PCD7BCLXQyLTRCNQ/SJRCQMi0UUKdCD+AJ2KGYPbiyRZg9udJEEjXP0Zg9ufJEIi0UIZg9w3QBmD3DOAGYPcNcA" + . "63V1IGYPbiyRZg9udJEEjXP0i0UIZg9w1QBmD3DOAOmAAAAAO1UUdBJmD248kYtFCGYPcM8A6YcAAACLRQjpnQAAAA8QAA8o4GYP" + . "duNmD9f8hf8PhYcAAAAPKOBmD3bhZg/X/IX/dXhmD3bCZg/X+IX/dWyDwBA58HLIg8ID6U3///8PEAAPKNpmD3bYZg/X+4X/dUtm" + . "D3bBZg/X+IX/dT+DwBA58HLbg8IC6SD///8PEABmD3bBZg/X8IX2dSGDwBCLdCQMOfBy5kLpAP///4s0kTkwdBFCO1UUdfODwAQ5" + . "2HMEMdLr8I1l9FteX13D" + : "VlNJicpIidEx0kyNWfREicgp0IP4AnYySGPCSI1Z9GZBD24sgGZBD25UgAhmD3DdAGZBD25sgARmD3DSAEyJ0GYPcM0A6YQAAAB1" + . "JkhjwkiNWfRmQQ9uLIBmQQ9uTIAETInQZg9w1QBmD3DJAOmLAAAARDnKdBZIY8JmQQ9uFIBMidBmD3DKAOmQAAAATInQ6akAAAAP" + . "EAAPKOBmD3bjZg/X9IX2D4WTAAAADyjgZg924WYP1/SF9g+FgAAAAGYPdsJmD9fwhfZ1dEiDwBBIOdhywoPCA+kz////DxAADyja" + . "Zg922GYP1/OF9nVRZg92wWYP1/CF9nVFSIPAEEg52HLZg8IC6QT///8PEABmD3bBZg/X2IXbdSVIg8AQTDnYcuj/wunl/v//SP/C" + . "QYtckPw5GHQSRDnKcu9Ig8AESDnIcwQx0uvuW17D") ; C source code - https://godbolt.org/z/oEGGeedac pixelsearch4 := this.Base64Code((A_PtrSize == 4) diff --git a/ImagePut.ahk b/ImagePut.ahk index 0e4dd5c1..fbfd109d 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2418,10 +2418,18 @@ class ImagePut { . "1GYP3tlmD3TQZg903A9U02YPdtVmRA/XwkWFwHUSSIPAEOvLikgCQTjLcwtIg8AESDnQcu/rHTjZcvGKSAFAOM5y6UA4+XLkighA" . "OM1y3UQ44XLYW15fXUFcQV1BXsM=") - ; C source code - https://godbolt.org/z/4hEhb7vG8 + ; C source code - https://godbolt.org/z/veshd46qn pixelsearch3 := this.Base64Code((A_PtrSize == 4) - ? "VYnlU4tNDItFCDnIcxkx0jtVFHQNi10QixyTORh0CELr7oPABOvjW13D" - : "SInISDnQcxwxyUQ5yXMPSP/BRYtUiPxEORB17usGSIPABOvfww==") + ? "VTHSieVXVlOD5PCD7BCLXQyLTRCNQ/SJRCQMi0UUKdCD+AJ2KGYPbiyRZg9udJEEjXP0Zg9ufJEIi0UIZg9w3QBmD3DOAGYPcNcA" + . "63V1IGYPbiyRZg9udJEEjXP0i0UIZg9w1QBmD3DOAOmAAAAAO1UUdBJmD248kYtFCGYPcM8A6YcAAACLRQjpnQAAAA8QAA8o4GYP" + . "duNmD9f8hf8PhYcAAAAPKOBmD3bhZg/X/IX/dXhmD3bCZg/X+IX/dWyDwBA58HLIg8ID6U3///8PEAAPKNpmD3bYZg/X+4X/dUtm" + . "D3bBZg/X+IX/dT+DwBA58HLbg8IC6SD///8PEABmD3bBZg/X8IX2dSGDwBCLdCQMOfBy5kLpAP///4s0kTkwdBFCO1UUdfODwAQ5" + . "2HMEMdLr8I1l9FteX13D" + : "VlNJicpIidEx0kyNWfREicgp0IP4AnYySGPCSI1Z9GZBD24sgGZBD25UgAhmD3DdAGZBD25sgARmD3DSAEyJ0GYPcM0A6YQAAAB1" + . "JkhjwkiNWfRmQQ9uLIBmQQ9uTIAETInQZg9w1QBmD3DJAOmLAAAARDnKdBZIY8JmQQ9uFIBMidBmD3DKAOmQAAAATInQ6akAAAAP" + . "EAAPKOBmD3bjZg/X9IX2D4WTAAAADyjgZg924WYP1/SF9g+FgAAAAGYPdsJmD9fwhfZ1dEiDwBBIOdhywoPCA+kz////DxAADyja" + . "Zg922GYP1/OF9nVRZg92wWYP1/CF9nVFSIPAEEg52HLZg8IC6QT///8PEABmD3bBZg/X2IXbdSVIg8AQTDnYcuj/wunl/v//SP/C" + . "QYtckPw5GHQSRDnKcu9Ig8AESDnIcwQx0uvuW17D") ; C source code - https://godbolt.org/z/oEGGeedac pixelsearch4 := this.Base64Code((A_PtrSize == 4) From 68ab4aae92fa6bb68ede284d1ada680b792b3c18 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 9 Sep 2023 09:41:53 -0400 Subject: [PATCH 429/492] Refactor WindowProc * Change window struct allocations * Differentiate between child and parent windows * Fix formatting of hexadecimals * Add middle click to show tooltip x, y, and color * Truncate most handles to 32-bits --- ImagePut (for v1).ahk | 162 +++++++++++++++++++++++++++------------- ImagePut.ahk | 168 ++++++++++++++++++++++++++++-------------- 2 files changed, 223 insertions(+), 107 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 4c278225..6419cd09 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2072,7 +2072,7 @@ class ImagePut { } __Get(x, y) { - return Format("0x{:X}", NumGet(this.ptr + 4*(y*this.width + x), "uint")) + return Format("0x{:08X}", NumGet(this.ptr + 4*(y*this.width + x), "uint")) } __Set(x, y, color) { @@ -2787,14 +2787,14 @@ class ImagePut { DllCall("SetWindowLong", "ptr", hwnd, "int", -20, "int", styleEx | WS_EX_LAYERED) DllCall("SetLayeredWindowAttributes", "ptr", hwnd, "uint", 0xF0F0F0, "uchar", 0, "int", 1) - ; Set itself as the *internal* top level window. - DllCall("SetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 0, "ptr", hwnd) - ; A layered child window is only available on Windows 8+. - hwnd_child := this.show(pBitmap, title, [0, 0, w, h], WS_CHILD | WS_VISIBLE, WS_EX_LAYERED, hwnd) + child := this.show(pBitmap, title, [0, 0, w, h], WS_CHILD | WS_VISIBLE, WS_EX_LAYERED, hwnd) - ; Override the child's internal hwnd with the parent's hwnd. - DllCall("SetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd_child, "int", 0, "ptr", hwnd) + ; Store extra data inside window struct (cbWndExtra). + DllCall("SetWindowLong", "ptr", hwnd, "int", 0*A_PtrSize, "ptr", hwnd) ; parent window + DllCall("SetWindowLong", "ptr", hwnd, "int", 1*A_PtrSize, "ptr", child) ; child window + DllCall("SetWindowLong", "ptr", child, "int", 0*A_PtrSize, "ptr", hwnd) ; parent window + DllCall("SetWindowLong", "ptr", child, "int", 1*A_PtrSize, "ptr", child) ; child window ; Prevent empty windows from showing. DllCall("ShowWindow", "ptr", hwnd, "int", 1) @@ -2933,15 +2933,17 @@ class ImagePut { , "uint*", 0xFF << 16 | 0x01 << 24 ; *pblend , "uint", 2) ; dwFlags - ; Set itself as the *internal* top level window. - DllCall("SetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 0, "ptr", hwnd) + ; Store extra data inside window struct (cbWndExtra). + DllCall("SetWindowLong", "ptr", hwnd, "int", 0*A_PtrSize, "ptr", hwnd) ; parent window (same, only 1 window for now) + DllCall("SetWindowLong", "ptr", hwnd, "int", 1*A_PtrSize, "ptr", hwnd) ; child window (same, only 1 window for now) + DllCall("SetWindowLong", "ptr", hwnd, "int", 2*A_PtrSize, "ptr", hdc) ; contains a pixel buffer ; Check for multiple frames. DllCall("gdiplus\GdipImageGetFrameDimensionsCount", "ptr", pBitmap, "uint*", dims:=0) DllCall("gdiplus\GdipImageGetFrameDimensionsList", "ptr", pBitmap, "ptr", &dimIDs := VarSetCapacity(dimIDs, 16*dims), "uint", dims) DllCall("gdiplus\GdipImageGetFrameCount", "ptr", pBitmap, "ptr", &dimIDs, "uint*", frames:=0) - ; For multiple frames, send WM_APP to WindowProc to render GIFs. + ; GIF Animations! if (frames > 1) { ; Save frame delays because they are slow enough to impact timing. DllCall("gdiplus\GdipGetPropertyItemSize", "ptr", pBitmap, "uint", 0x5100, "uint*", ItemSize:=0) ; PropertyTagFrameDelay @@ -2952,27 +2954,17 @@ class ImagePut { DllCall("gdiplus\GdipCloneImage", "ptr", pBitmap, "ptr*", pBitmapClone:=0) DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmapClone) - ; Store data inside window class extra bits (cbWndExtra). - DllCall("SetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 1*A_PtrSize, "ptr", pBitmapClone) - DllCall("SetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 2*A_PtrSize, "ptr", hdc) - DllCall("SetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 3*A_PtrSize, "ptr", Item) - DllCall("SetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 4*A_PtrSize, "ptr", pBits) + ; Store extra data inside window struct (cbWndExtra). + DllCall("SetWindowLong", "ptr", hwnd, "int", 3*A_PtrSize, "ptr", pBitmapClone) + DllCall("SetWindowLong", "ptr", hwnd, "int", 4*A_PtrSize, "ptr", Item) ; Preserve GDI+ scope. ImagePut.gdiplusStartup() - ; Goto WindowProc() and initiate animation via PostMessage. + ; Start animations using WM_APP in WindowProc(). DllCall("PostMessage", "ptr", hwnd, "uint", 0x8000, "uptr", -1, "ptr", 0) - - ; Avoid disposing the device context. - return hwnd } - ; Cleanup the hBitmap and device contexts. - DllCall("SelectObject", "ptr", hdc, "ptr", obm) - DllCall("DeleteObject", "ptr", hbm) - DllCall("DeleteDC", "ptr", hdc) - return hwnd } @@ -3025,50 +3017,108 @@ class ImagePut { ; WM_DESTROY if (uMsg = 0x2) { - if pBitmap := DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 1*A_PtrSize, "ptr") { - hdc := DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 2*A_PtrSize, "ptr") - Item := DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 3*A_PtrSize, "ptr") - - ; Exit loop. - DllCall("SetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 1*A_PtrSize, "ptr", 0) - - ; Dispose of all data stored in the window class. + ; Cleanup the hBitmap and device contexts. + hdc := DllCall("GetWindowLong", "ptr", hwnd, "int", 2*A_PtrSize, "ptr") + obm := DllCall("CreateBitmap", "int", 0, "int", 0, "uint", 1, "uint", 1, "ptr", 0, "ptr") + hbm := DllCall("SelectObject", "ptr", hdc, "ptr", obm, "ptr") + DllCall("DeleteObject", "ptr", hbm) + DllCall("DeleteDC", "ptr", hdc) + + ; Exit GIF Animation loop. + if pBitmap := DllCall("GetWindowLong", "ptr", hwnd, "int", 3*A_PtrSize, "ptr") { DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) - obm := DllCall("CreateBitmap", "int", 0, "int", 0, "uint", 1, "uint", 1, "ptr", 0, "ptr") - hbm := DllCall("SelectObject", "ptr", hdc, "ptr", obm, "ptr") - DllCall("DeleteObject", "ptr", hbm) - DllCall("DeleteDC", "ptr", hdc) + DllCall("SetWindowLong", "ptr", hwnd, "int", 3*A_PtrSize, "ptr", 0) ; Exit loop + + ; Delete Item. + Item := DllCall("GetWindowLong", "ptr", hwnd, "int", 4*A_PtrSize, "ptr") DllCall("GlobalFree", "ptr", Item) ; Exit GDI+ conditionally due to the ImagePut class being destroyed first. ImagePut.gdiplusShutdown() } - Hotkey % "^+F12", % void, Off ; Cannot disable, does nothing + + Hotkey % "^+F12", % void, Off ; Cannot disable script persistence, does nothing } - ; WM_LBUTTONDOWN + ; WM_LBUTTONDOWN - Drag to move the window. if (uMsg = 0x201) { - hwnd := DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 0, "ptr") ; internal parent hwnd - return DllCall("DefWindowProc", "ptr", hwnd, "uint", 0xA1, "uptr", 2, "ptr", 0, "ptr") + parent := DllCall("GetWindowLong", "ptr", hwnd, "int", 0*A_PtrSize, "ptr") + return DllCall("DefWindowProc", "ptr", parent, "uint", 0xA1, "uptr", 2, "ptr", 0, "ptr") } - ; WM_RBUTTONUP + ; WM_RBUTTONUP - Destroy the window. if (uMsg = 0x205) { - hwnd := DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 0, "ptr") ; internal parent hwnd - DllCall("DestroyWindow", "ptr", hwnd) + parent := DllCall("GetWindowLong", "ptr", hwnd, "int", 0*A_PtrSize, "ptr") + DllCall("DestroyWindow", "ptr", parent) return 0 } + + ; WM_MBUTTONDOWN - Show x, y, and color. + if (uMsg = 0x207) { + ; Force the child hwnd as transparent pixels could redirect to the parent hwnd. + child := DllCall("GetWindowLong", "ptr", hwnd, "int", 1*A_PtrSize, "ptr") + hdc := DllCall("GetWindowLong", "ptr", child, "int", 2*A_PtrSize, "ptr") + + ; Get pBits from hBitmap currently selected onto the device context. + ; struct DIBSECTION - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-dibsection + ; struct BITMAP - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmap + hbm := DllCall("GetCurrentObject", "ptr", hdc, "uint", 7) + VarSetCapacity(dib, size := 64+5*A_PtrSize) ; sizeof(DIBSECTION) = 84, 104 + DllCall("GetObject", "ptr", hbm, "int", size, "ptr", &dib) + , width := NumGet(dib, 4, "uint") + , height := NumGet(dib, 8, "uint") + , pBits := NumGet(dib, A_PtrSize = 4 ? 20:24, "ptr") + + ; Convert from unsigned int to signed shorts. + VarSetCapacity(xy, 4) + NumPut(lparam, xy, "uint") + x := NumGet(xy, 0, "short") + y := NumGet(xy, 2, "short") + + ; Safe limits for x and y. + (x < 0) && x := 0 + (x >= width) && x := width-1 + (y < 0) && y := 0 + (y >= height) && y := height-1 + + ; Get color. + c := Format("0x{:08X}", NumGet(pBits + 4*(y*width + x), "uint")) + + ; Process background color (BGR) and text color (greyscale). + background_color := RegExReplace(c, "^0x..(..)(..)(..)$", "0x$3$2$1") + text_color := (0.3*(255&c>>16) + 0.59*(255&c>>8) + 0.11*(255&c)) >= 128 ? 0x000000 : 0xFFFFFF + + ; Show tooltip. + Tooltip % " (" x ", " y ") `n " SubStr(c, 3) " " + tt := WinExist("ahk_class tooltips_class32 ahk_exe" A_AhkPath) + + ; Style background and text color. + DllCall("UxTheme\SetWindowTheme", "ptr", tt, "ptr", 0, "ptr", &empty := VarSetCapacity(2, 0), "uint") + DllCall("SendMessage", "ptr", tt, "uint", 1043, "ptr", background_color, "ptr", 0) + DllCall("SendMessage", "ptr", tt, "uint", 1044, "ptr", text_color, "ptr", 0) + + ; Destroy tooltip after 7 seconds of the last showing. + static tick + tick := A_TickCount + pWndProc := RegisterCallback(ImagePut.WindowProc,,, &ImagePut) + clock := Func("DllCall").bind(pWndProc, "ptr", hwnd, "uint", 0x8001, "uptr", A_TickCount, "ptr", 0) + SetTimer % clock, -7000 + DllCall("GlobalFree", "ptr", pWndProc, "ptr") + } + + if (uMsg = 0x8001) + if (tick == wParam) + Tooltip ; WM_APP - Animate GIFs - if (uMsg = 0x8000) { + if (uMsg = 0x8000) { ; Thanks tmplinshi, Teadrinker - https://www.autohotkey.com/boards/viewtopic.php?f=76&t=83358 Critical ; Get variables. - pBitmap := DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 1*A_PtrSize, "ptr") - hdc := DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 2*A_PtrSize, "ptr") - Item := DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 3*A_PtrSize, "ptr") - pBits := DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 4*A_PtrSize, "ptr") + hdc := DllCall("GetWindowLong", "ptr", hwnd, "int", 2*A_PtrSize, "ptr") + pBitmap := DllCall("GetWindowLong", "ptr", hwnd, "int", 3*A_PtrSize, "ptr") + Item := DllCall("GetWindowLong", "ptr", hwnd, "int", 4*A_PtrSize, "ptr") ; Exit loop. if !pBitmap @@ -3099,9 +3149,10 @@ class ImagePut { res := Ceil(delay / resolution) * resolution ; Async the next frame as soon as possible to prevent rendering lag. - static pWndProc := RegisterCallback(ImagePut.WindowProc,,, &ImagePut) + pWndProc := RegisterCallback(ImagePut.WindowProc,,, &ImagePut) next_frame := Func("DllCall").bind(pWndProc, "ptr", hwnd, "uint", uMsg, "uptr", frame, "ptr", 0) SetTimer % next_frame, % -1 * res + DllCall("GlobalFree", "ptr", pWndProc, "ptr") /* ; Debug code static start := 0, sum := 0, count := 0, sum2 := 0, count2 := 0 @@ -3128,9 +3179,15 @@ class ImagePut { DllCall("gdiplus\GdipImageGetFrameDimensionsList", "ptr", pBitmap, "ptr", &dimIDs := VarSetCapacity(dimIDs, 16*dims), "uint", dims) DllCall("gdiplus\GdipImageSelectActiveFrame", "ptr", pBitmap, "ptr", &dimIDs, "uint", frame) - ; Get Bitmap width and height. - DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0) - DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0) + ; Get pBits from hBitmap currently selected onto the device context. + ; struct DIBSECTION - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-dibsection + ; struct BITMAP - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmap + hbm := DllCall("GetCurrentObject", "ptr", hdc, "uint", 7) + VarSetCapacity(dib, size := 64+5*A_PtrSize) ; sizeof(DIBSECTION) = 84, 104 + DllCall("GetObject", "ptr", hbm, "int", size, "ptr", &dib) + , width := NumGet(dib, 4, "uint") + , height := NumGet(dib, 8, "uint") + , pBits := NumGet(dib, A_PtrSize = 4 ? 20:24, "ptr") ; Transfer data from source pBitmap to an hBitmap manually. VarSetCapacity(Rect, 16, 0) ; sizeof(Rect) = 16 @@ -3162,6 +3219,7 @@ class ImagePut { } ; Must return + default: return DllCall("DefWindowProc", "ptr", hwnd, "uint", uMsg, "uptr", wParam, "ptr", lParam, "ptr") } diff --git a/ImagePut.ahk b/ImagePut.ahk index fbfd109d..9da2cc94 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2072,7 +2072,7 @@ class ImagePut { } __Item[x, y] { - get => Format("0x{:X}", NumGet(this.ptr + 4*(y*this.width + x), "uint")) + get => Format("0x{:08X}", NumGet(this.ptr + 4*(y*this.width + x), "uint")) set => ((value >> 24) || value |= 0xFF000000, NumPut("uint", value, this.ptr + 4*(y*this.width + x)), value) @@ -2091,7 +2091,7 @@ class ImagePut { return False ; yield statements - c := Format("0x{:X}", NumGet(this, start, "uint")) + c := Format("0x{:08X}", NumGet(this, start, "uint")) ; do block start += 4 @@ -2109,7 +2109,7 @@ class ImagePut { ; yield statements i := start // 4 - c := Format("0x{:X}", NumGet(this, start, "uint")) + c := Format("0x{:08X}", NumGet(this, start, "uint")) ; do block start += 4 @@ -2129,7 +2129,7 @@ class ImagePut { i := start // 4 x := mod(i, this.width) y := i // this.width - c := Format("0x{:X}", NumGet(this, start, "uint")) + c := Format("0x{:08X}", NumGet(this, start, "uint")) ; do block start += 4 @@ -2149,7 +2149,7 @@ class ImagePut { i := start // 4 x := mod(i, this.width) y := i // this.width - c := Format("0x{:X}", NumGet(this, start, "uint")) + c := Format("0x{:08X}", NumGet(this, start, "uint")) r := c >> 16 & 0xFF g := c >> 8 & 0xFF b := c & 0xFF @@ -2172,7 +2172,7 @@ class ImagePut { i := start // 4 x := mod(i, this.width) y := i // this.width - c := Format("0x{:X}", NumGet(this, start, "uint")) + c := Format("0x{:08X}", NumGet(this, start, "uint")) r := c >> 16 & 0xFF g := c >> 8 & 0xFF b := c & 0xFF @@ -2787,16 +2787,16 @@ class ImagePut { DllCall("SetWindowLong", "ptr", hwnd, "int", -20, "int", styleEx | WS_EX_LAYERED) DllCall("SetLayeredWindowAttributes", "ptr", hwnd, "uint", 0xF0F0F0, "uchar", 0, "int", 1) - ; Set itself as the *internal* top level window. - DllCall("SetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 0, "ptr", hwnd) - ; A layered child window is only available on Windows 8+. - hwnd_child := this.show(pBitmap, title, [0, 0, w, h], WS_CHILD | WS_VISIBLE, WS_EX_LAYERED, hwnd) + child := this.show(pBitmap, title, [0, 0, w, h], WS_CHILD | WS_VISIBLE, WS_EX_LAYERED, hwnd) - ; Override the child's internal hwnd with the parent's hwnd. - DllCall("SetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd_child, "int", 0, "ptr", hwnd) + ; Store extra data inside window struct (cbWndExtra). + DllCall("SetWindowLong", "ptr", hwnd, "int", 0*A_PtrSize, "ptr", hwnd) ; parent window + DllCall("SetWindowLong", "ptr", hwnd, "int", 1*A_PtrSize, "ptr", child) ; child window + DllCall("SetWindowLong", "ptr", child, "int", 0*A_PtrSize, "ptr", hwnd) ; parent window + DllCall("SetWindowLong", "ptr", child, "int", 1*A_PtrSize, "ptr", child) ; child window - ; Prevent empty windows from showing. + ; Delaying this call prevents empty window borders from appearing. DllCall("ShowWindow", "ptr", hwnd, "int", 1) return hwnd @@ -2933,15 +2933,17 @@ class ImagePut { , "uint*", 0xFF << 16 | 0x01 << 24 ; *pblend , "uint", 2) ; dwFlags - ; Set itself as the *internal* top level window. - DllCall("SetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 0, "ptr", hwnd) + ; Store extra data inside window struct (cbWndExtra). + DllCall("SetWindowLong", "ptr", hwnd, "int", 0*A_PtrSize, "ptr", hwnd) ; parent window (same, only 1 window for now) + DllCall("SetWindowLong", "ptr", hwnd, "int", 1*A_PtrSize, "ptr", hwnd) ; child window (same, only 1 window for now) + DllCall("SetWindowLong", "ptr", hwnd, "int", 2*A_PtrSize, "ptr", hdc) ; contains a pixel buffer ; Check for multiple frames. DllCall("gdiplus\GdipImageGetFrameDimensionsCount", "ptr", pBitmap, "uint*", &dims:=0) DllCall("gdiplus\GdipImageGetFrameDimensionsList", "ptr", pBitmap, "ptr", dimIDs := Buffer(16*dims), "uint", dims) DllCall("gdiplus\GdipImageGetFrameCount", "ptr", pBitmap, "ptr", dimIDs, "uint*", &frames:=0) - ; For multiple frames, send WM_APP to WindowProc to render GIFs. + ; GIF Animations! if (frames > 1) { ; Save frame delays because they are slow enough to impact timing. DllCall("gdiplus\GdipGetPropertyItemSize", "ptr", pBitmap, "uint", 0x5100, "uint*", &ItemSize:=0) ; PropertyTagFrameDelay @@ -2952,27 +2954,17 @@ class ImagePut { DllCall("gdiplus\GdipCloneImage", "ptr", pBitmap, "ptr*", &pBitmapClone:=0) DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmapClone) - ; Store data inside window class extra bits (cbWndExtra). - DllCall("SetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 1*A_PtrSize, "ptr", pBitmapClone) - DllCall("SetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 2*A_PtrSize, "ptr", hdc) - DllCall("SetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 3*A_PtrSize, "ptr", Item) - DllCall("SetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 4*A_PtrSize, "ptr", pBits) + ; Store extra data inside window struct (cbWndExtra). + DllCall("SetWindowLong", "ptr", hwnd, "int", 3*A_PtrSize, "ptr", pBitmapClone) + DllCall("SetWindowLong", "ptr", hwnd, "int", 4*A_PtrSize, "ptr", Item) ; Preserve GDI+ scope. ImagePut.gdiplusStartup() - ; Goto WindowProc() and initiate animation via PostMessage. + ; Start animations using WM_APP in WindowProc(). DllCall("PostMessage", "ptr", hwnd, "uint", 0x8000, "uptr", -1, "ptr", 0) - - ; Avoid disposing the device context. - return hwnd } - ; Cleanup the hBitmap and device contexts. - DllCall("SelectObject", "ptr", hdc, "ptr", obm) - DllCall("DeleteObject", "ptr", hbm) - DllCall("DeleteDC", "ptr", hdc) - return hwnd } @@ -3025,50 +3017,108 @@ class ImagePut { ; WM_DESTROY if (uMsg = 0x2) { - if pBitmap := DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 1*A_PtrSize, "ptr") { - hdc := DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 2*A_PtrSize, "ptr") - Item := DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 3*A_PtrSize, "ptr") - - ; Exit loop. - DllCall("SetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 1*A_PtrSize, "ptr", 0) - - ; Dispose of all data stored in the window class. + ; Cleanup the hBitmap and device contexts. + hdc := DllCall("GetWindowLong", "ptr", hwnd, "int", 2*A_PtrSize, "ptr") + obm := DllCall("CreateBitmap", "int", 0, "int", 0, "uint", 1, "uint", 1, "ptr", 0, "ptr") + hbm := DllCall("SelectObject", "ptr", hdc, "ptr", obm, "ptr") + DllCall("DeleteObject", "ptr", hbm) + DllCall("DeleteDC", "ptr", hdc) + + ; Exit GIF Animation loop. + if pBitmap := DllCall("GetWindowLong", "ptr", hwnd, "int", 3*A_PtrSize, "ptr") { DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) - obm := DllCall("CreateBitmap", "int", 0, "int", 0, "uint", 1, "uint", 1, "ptr", 0, "ptr") - hbm := DllCall("SelectObject", "ptr", hdc, "ptr", obm, "ptr") - DllCall("DeleteObject", "ptr", hbm) - DllCall("DeleteDC", "ptr", hdc) + DllCall("SetWindowLong", "ptr", hwnd, "int", 3*A_PtrSize, "ptr", 0) ; Exit loop + + ; Delete Item. + Item := DllCall("GetWindowLong", "ptr", hwnd, "int", 4*A_PtrSize, "ptr") DllCall("GlobalFree", "ptr", Item) ; Exit GDI+ conditionally due to the ImagePut class being destroyed first. ImagePut.gdiplusShutdown() } + Persistent(--active_windows) } - ; WM_LBUTTONDOWN + ; WM_LBUTTONDOWN - Drag to move the window. if (uMsg = 0x201) { - hwnd := DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 0, "ptr") ; internal parent hwnd - return DllCall("DefWindowProc", "ptr", hwnd, "uint", 0xA1, "uptr", 2, "ptr", 0, "ptr") + parent := DllCall("GetWindowLong", "ptr", hwnd, "int", 0*A_PtrSize, "ptr") + return DllCall("DefWindowProc", "ptr", parent, "uint", 0xA1, "uptr", 2, "ptr", 0, "ptr") } - ; WM_RBUTTONUP + ; WM_RBUTTONUP - Destroy the window. if (uMsg = 0x205) { - hwnd := DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 0, "ptr") ; internal parent hwnd - DllCall("DestroyWindow", "ptr", hwnd) + parent := DllCall("GetWindowLong", "ptr", hwnd, "int", 0*A_PtrSize, "ptr") + DllCall("DestroyWindow", "ptr", parent) return 0 } + ; WM_MBUTTONDOWN - Show x, y, and color. + if (uMsg = 0x207) { + ; Force the child hwnd as transparent pixels could redirect to the parent hwnd. + child := DllCall("GetWindowLong", "ptr", hwnd, "int", 1*A_PtrSize, "ptr") + hdc := DllCall("GetWindowLong", "ptr", child, "int", 2*A_PtrSize, "ptr") + + ; Get pBits from hBitmap currently selected onto the device context. + ; struct DIBSECTION - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-dibsection + ; struct BITMAP - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmap + hbm := DllCall("GetCurrentObject", "ptr", hdc, "uint", 7) + dib := Buffer(64+5*A_PtrSize) ; sizeof(DIBSECTION) = 84, 104 + DllCall("GetObject", "ptr", hbm, "int", dib.size, "ptr", dib) + , width := NumGet(dib, 4, "uint") + , height := NumGet(dib, 8, "uint") + , pBits := NumGet(dib, A_PtrSize = 4 ? 20:24, "ptr") + + ; Convert from unsigned int to signed shorts. + xy := Buffer(4) + NumPut("uint", lparam, xy) + x := NumGet(xy, 0, "short") + y := NumGet(xy, 2, "short") + + ; Safe limits for x and y. + (x < 0) && x := 0 + (x >= width) && x := width-1 + (y < 0) && y := 0 + (y >= height) && y := height-1 + + ; Get color. + c := Format("0x{:08X}", NumGet(pBits + 4*(y*width + x), "uint")) + + ; Process background color (BGR) and text color (greyscale). + background_color := RegExReplace(c, "^0x..(..)(..)(..)$", "0x$3$2$1") + text_color := (0.3*(255&c>>16) + 0.59*(255&c>>8) + 0.11*(255&c)) >= 128 ? 0x000000 : 0xFFFFFF + + ; Show tooltip. + tt := Tooltip(" (" x ", " y ") `n " SubStr(c, 3) " ") + + + ; Style background and text color. + DllCall("UxTheme\SetWindowTheme", "ptr", tt, "ptr", 0, "ptr", Buffer(2, 0), "hresult") + DllCall("SendMessage", "ptr", tt, "uint", 1043, "ptr", background_color, "ptr", 0) + DllCall("SendMessage", "ptr", tt, "uint", 1044, "ptr", text_color, "ptr", 0) + + ; Destroy tooltip after 7 seconds of the last showing. + static tick ; Using a static allows changes in value to affect tick inside the closure. + tick := A_TickCount ; Change and update tick. tock is set only once using bind to eval A_TickCount. + SetTimer (tock => (tick == tock) && Tooltip()).Bind(A_TickCount), -7000 + } + + + + + + + + ; WM_APP - Animate GIFs if (uMsg = 0x8000) { ; Thanks tmplinshi, Teadrinker - https://www.autohotkey.com/boards/viewtopic.php?f=76&t=83358 Critical ; Get variables. - pBitmap := DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 1*A_PtrSize, "ptr") - hdc := DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 2*A_PtrSize, "ptr") - Item := DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 3*A_PtrSize, "ptr") - pBits := DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr":""), "ptr", hwnd, "int", 4*A_PtrSize, "ptr") + hdc := DllCall("GetWindowLong", "ptr", hwnd, "int", 2*A_PtrSize, "ptr") + pBitmap := DllCall("GetWindowLong", "ptr", hwnd, "int", 3*A_PtrSize, "ptr") + Item := DllCall("GetWindowLong", "ptr", hwnd, "int", 4*A_PtrSize, "ptr") ; Exit loop. if !pBitmap @@ -3102,6 +3152,7 @@ class ImagePut { SetTimer WindowProc.bind(hwnd, uMsg, frame, 0), -1 * res + /* ; Debug code static start := 0, sum := 0, count := 0, sum2 := 0, count2 := 0 @@ -3128,9 +3179,15 @@ class ImagePut { DllCall("gdiplus\GdipImageGetFrameDimensionsList", "ptr", pBitmap, "ptr", dimIDs := Buffer(16*dims), "uint", dims) DllCall("gdiplus\GdipImageSelectActiveFrame", "ptr", pBitmap, "ptr", dimIDs, "uint", frame) - ; Get Bitmap width and height. - DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", &width:=0) - DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", &height:=0) + ; Get pBits from hBitmap currently selected onto the device context. + ; struct DIBSECTION - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-dibsection + ; struct BITMAP - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmap + hbm := DllCall("GetCurrentObject", "ptr", hdc, "uint", 7) + dib := Buffer(64+5*A_PtrSize) ; sizeof(DIBSECTION) = 84, 104 + DllCall("GetObject", "ptr", hbm, "int", dib.size, "ptr", dib) + , width := NumGet(dib, 4, "uint") + , height := NumGet(dib, 8, "uint") + , pBits := NumGet(dib, A_PtrSize = 4 ? 20:24, "ptr") ; Transfer data from source pBitmap to an hBitmap manually. Rect := Buffer(16, 0) ; sizeof(Rect) = 16 @@ -3162,6 +3219,7 @@ class ImagePut { } ; Must return + default: return DllCall("DefWindowProc", "ptr", hwnd, "uint", uMsg, "uptr", wParam, "ptr", lParam, "ptr") } } From 3044eb0ab4e8e8ee198fa629d5643b1de346047c Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 9 Sep 2023 09:49:04 -0400 Subject: [PATCH 430/492] trailing spaces --- ImagePut (for v1).ahk | 14 +++++++------- ImagePut.ahk | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 6419cd09..9bf55da5 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -773,7 +773,7 @@ class ImagePut { ; Force downscaling. if (direction < 0 and (safe_w > width && safe_h > height)) return pBitmap - + ; Create a new bitmap and get the graphics context. DllCall("gdiplus\GdipCreateBitmapFromScan0" , "int", safe_w, "int", safe_h, "int", 0, "int", format, "ptr", 0, "ptr*", pBitmapScale:=0) @@ -2412,7 +2412,7 @@ class ImagePut { ? "VWYPduSJ5VdWU4Pk8IPsEIpFFItdEItNGItVHIt1DIt9IIhEJA6KRSSIXCQPD7bbiEwkDcHjEA+2yYhEJAsPtkUgweEIiFQkDA+2" . "0gnYweIICcgPtk0kDQAAAP8J0Q+2VRRmD27oi0UIZg9wzQDB4hAJ0Y1W9GYPbvFmD3DWADnQczkPEAAPEBgPEDhmD97BZg/e2mYP" . "dMFmD3TfD1TDZg92xGYP18iFyXURg8AQ68+KUAI4VCQPcwmDwAQ58HLw6yM6VCQOcvGKUAE4VCQNcug6VCQMcuKKEIn5ONFy2jpU" - . "JAty1I1l9FteX13D" + . "JAty1I1l9FteX13D" : "QVZBVUFUVVdWU0SLbCRgi0QkaESLdCRwRItUJHhEie6Jx0UPtu0PtsBBweUIRIn1RQ+29kWJ1EWJw0UPtsBEicvB4AhBweAQRQ+2" . "0kUPtslFCfBECdBBweEQRQnoRAnIQYHIAAAA/2YPbuhIichmQQ9uyEiNSvRmD3DBAGYPcM0AZg927Ug5yHM8DxAgDyjQDyjcZg/e" . "1GYP3tlmD3TQZg903A9U02YPdtVmRA/XwkWFwHUSSIPAEOvLikgCQTjLcwtIg8AESDnQcu/rHTjZcvGKSAFAOM5y6UA4+XLkighA" @@ -3052,7 +3052,7 @@ class ImagePut { DllCall("DestroyWindow", "ptr", parent) return 0 } - + ; WM_MBUTTONDOWN - Show x, y, and color. if (uMsg = 0x207) { ; Force the child hwnd as transparent pixels could redirect to the parent hwnd. @@ -3105,13 +3105,13 @@ class ImagePut { SetTimer % clock, -7000 DllCall("GlobalFree", "ptr", pWndProc, "ptr") } - + if (uMsg = 0x8001) if (tick == wParam) Tooltip ; WM_APP - Animate GIFs - if (uMsg = 0x8000) { + if (uMsg = 0x8000) { ; Thanks tmplinshi, Teadrinker - https://www.autohotkey.com/boards/viewtopic.php?f=76&t=83358 Critical @@ -3123,7 +3123,7 @@ class ImagePut { ; Exit loop. if !pBitmap return - + ; Get next frame. frames := NumGet(Item + 4, "uint") // 4 ; Max frames frame := wParam + 1 ; Next frame @@ -3935,7 +3935,7 @@ class ImagePut { - + ; Startup gdiplus when counter rises from 0 -> 1. if (instances = 0 && vary = 1) { diff --git a/ImagePut.ahk b/ImagePut.ahk index 9da2cc94..9bab67cd 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2412,7 +2412,7 @@ class ImagePut { ? "VWYPduSJ5VdWU4Pk8IPsEIpFFItdEItNGItVHIt1DIt9IIhEJA6KRSSIXCQPD7bbiEwkDcHjEA+2yYhEJAsPtkUgweEIiFQkDA+2" . "0gnYweIICcgPtk0kDQAAAP8J0Q+2VRRmD27oi0UIZg9wzQDB4hAJ0Y1W9GYPbvFmD3DWADnQczkPEAAPEBgPEDhmD97BZg/e2mYP" . "dMFmD3TfD1TDZg92xGYP18iFyXURg8AQ68+KUAI4VCQPcwmDwAQ58HLw6yM6VCQOcvGKUAE4VCQNcug6VCQMcuKKEIn5ONFy2jpU" - . "JAty1I1l9FteX13D" + . "JAty1I1l9FteX13D" : "QVZBVUFUVVdWU0SLbCRgi0QkaESLdCRwRItUJHhEie6Jx0UPtu0PtsBBweUIRIn1RQ+29kWJ1EWJw0UPtsBEicvB4AhBweAQRQ+2" . "0kUPtslFCfBECdBBweEQRQnoRAnIQYHIAAAA/2YPbuhIichmQQ9uyEiNSvRmD3DBAGYPcM0AZg927Ug5yHM8DxAgDyjQDyjcZg/e" . "1GYP3tlmD3TQZg903A9U02YPdtVmRA/XwkWFwHUSSIPAEOvLikgCQTjLcwtIg8AESDnQcu/rHTjZcvGKSAFAOM5y6UA4+XLkighA" From 9a30949b86ee09ea7e56fb2db7be6a0a43edc45f Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 9 Sep 2023 10:00:50 -0400 Subject: [PATCH 431/492] add comment about 64 to 32 bits truncation --- ImagePut (for v1).ahk | 1 + ImagePut.ahk | 1 + 2 files changed, 2 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 9bf55da5..5b081c88 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2934,6 +2934,7 @@ class ImagePut { , "uint", 2) ; dwFlags ; Store extra data inside window struct (cbWndExtra). + ; For 64 -> 32-bit: https://learn.microsoft.com/en-us/windows/win32/winprog64/interprocess-communication DllCall("SetWindowLong", "ptr", hwnd, "int", 0*A_PtrSize, "ptr", hwnd) ; parent window (same, only 1 window for now) DllCall("SetWindowLong", "ptr", hwnd, "int", 1*A_PtrSize, "ptr", hwnd) ; child window (same, only 1 window for now) DllCall("SetWindowLong", "ptr", hwnd, "int", 2*A_PtrSize, "ptr", hdc) ; contains a pixel buffer diff --git a/ImagePut.ahk b/ImagePut.ahk index 9bab67cd..3d09b29d 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2934,6 +2934,7 @@ class ImagePut { , "uint", 2) ; dwFlags ; Store extra data inside window struct (cbWndExtra). + ; For 64 -> 32-bit: https://learn.microsoft.com/en-us/windows/win32/winprog64/interprocess-communication DllCall("SetWindowLong", "ptr", hwnd, "int", 0*A_PtrSize, "ptr", hwnd) ; parent window (same, only 1 window for now) DllCall("SetWindowLong", "ptr", hwnd, "int", 1*A_PtrSize, "ptr", hwnd) ; child window (same, only 1 window for now) DllCall("SetWindowLong", "ptr", hwnd, "int", 2*A_PtrSize, "ptr", hdc) ; contains a pixel buffer From 2c68f0ac7819a81a9c0eb16c5230d35c0cb91d13 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 9 Sep 2023 15:15:46 -0400 Subject: [PATCH 432/492] Removing some aspects of RegisterSyncCallback seems to work... --- ImagePut.ahk | 161 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 140 insertions(+), 21 deletions(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index 3d09b29d..867d3d92 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2944,6 +2944,88 @@ class ImagePut { DllCall("gdiplus\GdipImageGetFrameDimensionsList", "ptr", pBitmap, "ptr", dimIDs := Buffer(16*dims), "uint", dims) DllCall("gdiplus\GdipImageGetFrameCount", "ptr", pBitmap, "ptr", dimIDs, "uint*", &frames:=0) + + static RegisterSyncCallback(funcObj, hwnd) { + static msg := 0x8000, SendMessageW := 0 + + (!IsSet(paramCount) && paramCount := funcObj.MinParams) + if IsSet(paramCount) && paramCount > funcObj.MaxParams { + throw ValueError('Incorrect paramCount', paramCount) + } + + hModule := DllCall('GetModuleHandle', 'Str', 'user32.dll', 'Ptr') + SendMessageW := DllCall('GetProcAddress', 'Ptr', hModule, 'AStr', 'SendMessageW', 'Ptr') + + pcb := DllCall('GlobalAlloc', 'UInt', 0, 'Ptr', 96, 'Ptr') + DllCall('VirtualProtect', 'Ptr', pcb, 'Ptr', 96, 'UInt', 0x40, 'UInt*', 0) + + p := pcb + if A_PtrSize = 8 { + /* + 48 89 4c 24 08 ; mov [rsp+8], rcx + 48 89 54'24 10 ; mov [rsp+16], rdx + 4c 89 44 24 18 ; mov [rsp+24], r8 + 4c'89 4c 24 20 ; mov [rsp+32], r9 + 48 83 ec 28' ; sub rsp, 40 + 4c 8d 44 24 30 ; lea r8, [rsp+48] (arg 3, ¶ms) + 49 b9 .. ; mov r9, .. (arg 4, operand to follow) + */ + p := NumPut('Ptr' , 0x54894808244c8948, + 'Ptr' , 0x4c182444894c1024, + 'Ptr' , 0x28ec834820244c89, + 'Ptr' , 0x00b9493024448d4c, p) - 1 + lParamPtr := p, p += 8 + + p := NumPut('Char' , 0xba, ; mov edx, nmsg + 'Int' , msg, + 'Char' , 0xb9, ; mov ecx, hwnd + 'Int' , hwnd, + 'Short', 0xb848, ; mov rax, SendMessageW + 'Ptr' , SendMessageW, + /* + ff d0 ; call rax + 48 83 c4 28 ; add rsp, 40 + c3 ; ret + */ + 'Ptr' , 0x00c328c48348d0ff, p) + } else { + p := NumPut('Char' , 0x68, p) ; push ... (lParam data) + lParamPtr := p, p += 4 + p := NumPut('Int' , 0x0824448d, ; lea eax, [esp+8] + 'Char' , 0x50, ; push eax + 'Char' , 0x68, ; push nmsg + 'Int' , msg, + 'Char' , 0x68, ; push hwnd + 'Int' , hwnd, + 'Char' , 0xb8, ; mov eax, &SendMessageW + 'Int' , SendMessageW, + 'Short', 0xd0ff, ; call eax + 'Char' , 0xc2, ; ret argsize + 'Short', ParamCount * 4, p) ; InStr(Options, 'C') ? 0 : + } + NumPut('Ptr', p, lParamPtr) + NumPut('Ptr', ObjPtrAddRef(funcObj), + 'Int', paramCount, p) + return pcb + /* + + + RegisterSyncCallback_Msg(wParam, lParam, msg, hwnd) { + MsgBox hwnd ", " msg ", " wParam ", " lParam + if hwnd != wnd.hwnd { + return + } + fn := ObjFromPtrAddRef(NumGet(lParam, 'Ptr')) + paramCount := NumGet(lParam, A_PtrSize, 'Int') + params := [] + Loop paramCount { + params.Push(NumGet(wParam, A_PtrSize * (A_Index - 1), 'Ptr')) + } + return fn(params*) + } + */ + } + ; GIF Animations! if (frames > 1) { ; Save frame delays because they are slow enough to impact timing. @@ -2955,15 +3037,31 @@ class ImagePut { DllCall("gdiplus\GdipCloneImage", "ptr", pBitmap, "ptr*", &pBitmapClone:=0) DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmapClone) - ; Store extra data inside window struct (cbWndExtra). - DllCall("SetWindowLong", "ptr", hwnd, "int", 3*A_PtrSize, "ptr", pBitmapClone) - DllCall("SetWindowLong", "ptr", hwnd, "int", 4*A_PtrSize, "ptr", Item) + pTimeProc := RegisterSyncCallback(TimeProc, hwnd) + + ; Allocate a private struct. + ptr := DllCall("GlobalAlloc", "uint", 0, "uptr", 4*A_PtrSize, "ptr") + NumPut("int", -1, ptr, 0*A_PtrSize) ; current frame + NumPut("ptr", pBitmapClone, ptr, 1*A_PtrSize) ; rest of GIF frames + NumPut("ptr", Item, ptr, 2*A_PtrSize) ; frame delays + NumPut("ptr", pTimeProc, ptr, 3*A_PtrSize) ; timer callback + DllCall("SetWindowLong", "ptr", hwnd, "int", 3*A_PtrSize, "ptr", ptr) ; Preserve GDI+ scope. ImagePut.gdiplusStartup() + DllCall("winmm\timeBeginPeriod", "uint", 10) + DllCall("winmm\timeSetEvent" + , "uint", 1 ; uDelay + , "uint", 10 ; uResolution + , "ptr", pTimeProc ; lpTimeProc + , "uint", hwnd ; dwUser + , "uint", 0 ; fuEvent + , "uint") + } - ; Start animations using WM_APP in WindowProc(). - DllCall("PostMessage", "ptr", hwnd, "uint", 0x8000, "uptr", -1, "ptr", 0) + ; WM_APP - Animate GIFs + static TimeProc(uTimerID, uMsg, hwnd, dw1, dw2) { + DllCall("PostMessage", "ptr", hwnd, "uint", 0x8000, "uptr", uTimerID, "ptr", 0) } return hwnd @@ -3108,18 +3206,17 @@ class ImagePut { - - - - ; WM_APP - Animate GIFs if (uMsg = 0x8000) { ; Thanks tmplinshi, Teadrinker - https://www.autohotkey.com/boards/viewtopic.php?f=76&t=83358 Critical ; Get variables. hdc := DllCall("GetWindowLong", "ptr", hwnd, "int", 2*A_PtrSize, "ptr") - pBitmap := DllCall("GetWindowLong", "ptr", hwnd, "int", 3*A_PtrSize, "ptr") - Item := DllCall("GetWindowLong", "ptr", hwnd, "int", 4*A_PtrSize, "ptr") + ptr := DllCall("GetWindowLong", "ptr", hwnd, "int", 3*A_PtrSize, "ptr") + , frame := NumGet(ptr, 0*A_PtrSize, "int") + , pBitmap := NumGet(ptr, 1*A_PtrSize, "ptr") + , Item := NumGet(ptr, 2*A_PtrSize, "ptr") + , pTimeProc := NumGet(ptr, 3*A_PtrSize, "ptr") ; Exit loop. if !pBitmap @@ -3127,8 +3224,10 @@ class ImagePut { ; Get next frame. frames := NumGet(Item + 4, "uint") // 4 ; Max frames - frame := wParam + 1 ; Next frame - frame := mod(frame, frames) ; Loop back to first frame + ;frame += 1 ; Next frame + frame := mod(frame + 1, frames) ; Loop back to first frame + NumPut("int", frame, ptr, 0*A_PtrSize) + ; Get delay. delays := NumGet(Item + 8 + A_PtrSize, "ptr") ; Array of delays @@ -3137,6 +3236,9 @@ class ImagePut { (delay == 10) && delay := 100 ; 10 ms is actually 100 ms ; See: https://www.biphelps.com/blog/The-Fastest-GIF-Does-Not-Exist + + + /* ; Randomize the delay in intervals of 15.6 resolution := 15.6 rand := random() @@ -3148,13 +3250,22 @@ class ImagePut { res := Floor(delay / resolution) * resolution else res := Ceil(delay / resolution) * resolution +*/ + ; Async the next frame as soon as possible to prevent rendering lag. + ;SetTimer WindowProc.bind(hwnd, uMsg, 0, 0), -1 * delay - ; Async the next frame as soon as possible to prevent rendering lag. - SetTimer WindowProc.bind(hwnd, uMsg, frame, 0), -1 * res + DllCall("winmm\timeKillEvent", "uint", wparam) ; Kill previous timer + + r := DllCall("winmm\timeSetEvent" + , "uint", delay-3.1 ; uDelay + , "uint", 1 ; uResolution + , "ptr", pTimeProc ; lpTimeProc + , "uint", hwnd ; dwUser + , "uint", 0 ; fuEvent + , "uint") - /* ; Debug code static start := 0, sum := 0, count := 0, sum2 := 0, count2 := 0 DllCall("QueryPerformanceFrequency", "int64*", &frequency:=0) @@ -3164,17 +3275,23 @@ class ImagePut { sum += time count++ average := sum / count - sum2 += res + sum2 += delay-3.1 ; change this to res or delay count2++ + if count > 1000 Tooltip "Current Tick:`t" Round(time, 4) . "`nAverage FPS:`t" Round(average, 4) . "`nQueued FPS:`t" Round(sum2 / count2, 4) . "`nTarget FPS:`t" delay - . "`nPercentage:`t" percentage ", " rand - . "`nFloor and Ceiling:`t" Floor(delay / resolution) * resolution ", " Ceil(delay / resolution) * resolution + ; "`nPercentage:`t" percentage ", " rand + ; "`nFloor and Ceiling:`t" Floor(delay / resolution) * resolution ", " Ceil(delay / resolution) * resolution } start := now - */ + + + + + + ; Select frame to show. DllCall("gdiplus\GdipImageGetFrameDimensionsCount", "ptr", pBitmap, "uint*", &dims:=0) DllCall("gdiplus\GdipImageGetFrameDimensionsList", "ptr", pBitmap, "ptr", dimIDs := Buffer(16*dims), "uint", dims) @@ -3216,9 +3333,11 @@ class ImagePut { , "uint", 0 ; crKey , "uint*", 0xFF << 16 | 0x01 << 24 ; *pblend , "uint", 2) ; dwFlags - return + } + + ; Must return default: return DllCall("DefWindowProc", "ptr", hwnd, "uint", uMsg, "uptr", wParam, "ptr", lParam, "ptr") From d2593143812f1d387d927773f2900a27e5bf162d Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 9 Sep 2023 15:32:39 -0400 Subject: [PATCH 433/492] Fix instability due to freeing callbacks --- ImagePut (for v1).ahk | 4 +- ImagePut.ahk | 92 ++++++++++++++++--------------------------- 2 files changed, 36 insertions(+), 60 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 5b081c88..320d4099 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -3104,7 +3104,7 @@ class ImagePut { pWndProc := RegisterCallback(ImagePut.WindowProc,,, &ImagePut) clock := Func("DllCall").bind(pWndProc, "ptr", hwnd, "uint", 0x8001, "uptr", A_TickCount, "ptr", 0) SetTimer % clock, -7000 - DllCall("GlobalFree", "ptr", pWndProc, "ptr") + ;DllCall("GlobalFree", "ptr", pWndProc, "ptr") } if (uMsg = 0x8001) @@ -3153,7 +3153,7 @@ class ImagePut { pWndProc := RegisterCallback(ImagePut.WindowProc,,, &ImagePut) next_frame := Func("DllCall").bind(pWndProc, "ptr", hwnd, "uint", uMsg, "uptr", frame, "ptr", 0) SetTimer % next_frame, % -1 * res - DllCall("GlobalFree", "ptr", pWndProc, "ptr") + ; DllCall("GlobalFree", "ptr", pWndProc, "ptr") /* ; Debug code static start := 0, sum := 0, count := 0, sum2 := 0, count2 := 0 diff --git a/ImagePut.ahk b/ImagePut.ahk index 867d3d92..0d2c757a 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2945,22 +2945,15 @@ class ImagePut { DllCall("gdiplus\GdipImageGetFrameCount", "ptr", pBitmap, "ptr", dimIDs, "uint*", &frames:=0) - static RegisterSyncCallback(funcObj, hwnd) { - static msg := 0x8000, SendMessageW := 0 - - (!IsSet(paramCount) && paramCount := funcObj.MinParams) - if IsSet(paramCount) && paramCount > funcObj.MaxParams { - throw ValueError('Incorrect paramCount', paramCount) - } + static RegisterSyncCallback(hwnd, msg) { + hModule := DllCall("GetModuleHandle", "str", "user32.dll", "ptr") + SendMessageW := DllCall("GetProcAddress", "ptr", hModule, "astr", "SendMessageW", "ptr") - hModule := DllCall('GetModuleHandle', 'Str', 'user32.dll', 'Ptr') - SendMessageW := DllCall('GetProcAddress', 'Ptr', hModule, 'AStr', 'SendMessageW', 'Ptr') - - pcb := DllCall('GlobalAlloc', 'UInt', 0, 'Ptr', 96, 'Ptr') - DllCall('VirtualProtect', 'Ptr', pcb, 'Ptr', 96, 'UInt', 0x40, 'UInt*', 0) + pcb := DllCall("GlobalAlloc", "uint", 0, "ptr", 96, "ptr") + DllCall("VirtualProtect", "ptr", pcb, "ptr", 96, "uint", 0x40, "uint*", 0) p := pcb - if A_PtrSize = 8 { + if (A_PtrSize = 8) { /* 48 89 4c 24 08 ; mov [rsp+8], rcx 48 89 54'24 10 ; mov [rsp+16], rdx @@ -2970,61 +2963,42 @@ class ImagePut { 4c 8d 44 24 30 ; lea r8, [rsp+48] (arg 3, ¶ms) 49 b9 .. ; mov r9, .. (arg 4, operand to follow) */ - p := NumPut('Ptr' , 0x54894808244c8948, - 'Ptr' , 0x4c182444894c1024, - 'Ptr' , 0x28ec834820244c89, - 'Ptr' , 0x00b9493024448d4c, p) - 1 + p := NumPut("ptr" , 0x54894808244c8948, + "ptr" , 0x4c182444894c1024, + "ptr" , 0x28ec834820244c89, + "ptr" , 0x00b9493024448d4c, p) - 1 lParamPtr := p, p += 8 - p := NumPut('Char' , 0xba, ; mov edx, nmsg - 'Int' , msg, - 'Char' , 0xb9, ; mov ecx, hwnd - 'Int' , hwnd, - 'Short', 0xb848, ; mov rax, SendMessageW - 'Ptr' , SendMessageW, + p := NumPut("char" , 0xba, ; mov edx, nmsg + "int" , msg, + "char" , 0xb9, ; mov ecx, hwnd + "int" , hwnd, + "short", 0xb848, ; mov rax, SendMessageW + "ptr" , SendMessageW, /* ff d0 ; call rax 48 83 c4 28 ; add rsp, 40 c3 ; ret */ - 'Ptr' , 0x00c328c48348d0ff, p) + "ptr" , 0x00c328c48348d0ff, p) } else { - p := NumPut('Char' , 0x68, p) ; push ... (lParam data) + p := NumPut("char" , 0x68, p) ; push ... (lParam data) lParamPtr := p, p += 4 - p := NumPut('Int' , 0x0824448d, ; lea eax, [esp+8] - 'Char' , 0x50, ; push eax - 'Char' , 0x68, ; push nmsg - 'Int' , msg, - 'Char' , 0x68, ; push hwnd - 'Int' , hwnd, - 'Char' , 0xb8, ; mov eax, &SendMessageW - 'Int' , SendMessageW, - 'Short', 0xd0ff, ; call eax - 'Char' , 0xc2, ; ret argsize - 'Short', ParamCount * 4, p) ; InStr(Options, 'C') ? 0 : + p := NumPut("int" , 0x0824448d, ; lea eax, [esp+8] + "char" , 0x50, ; push eax + "char" , 0x68, ; push nmsg + "int" , msg, + "char" , 0x68, ; push hwnd + "int" , hwnd, + "char" , 0xb8, ; mov eax, &SendMessageW + "int" , SendMessageW, + "short", 0xd0ff, ; call eax + "char" , 0xc2, ; ret argsize + "short", 0, p) ; InStr(Options, "C") ? 0 : ParamCount * 4 } - NumPut('Ptr', p, lParamPtr) - NumPut('Ptr', ObjPtrAddRef(funcObj), - 'Int', paramCount, p) + NumPut("ptr", p, lParamPtr) return pcb - /* - - - RegisterSyncCallback_Msg(wParam, lParam, msg, hwnd) { - MsgBox hwnd ", " msg ", " wParam ", " lParam - if hwnd != wnd.hwnd { - return - } - fn := ObjFromPtrAddRef(NumGet(lParam, 'Ptr')) - paramCount := NumGet(lParam, A_PtrSize, 'Int') - params := [] - Loop paramCount { - params.Push(NumGet(wParam, A_PtrSize * (A_Index - 1), 'Ptr')) - } - return fn(params*) - } - */ - } + } ; GIF Animations! if (frames > 1) { @@ -3037,7 +3011,7 @@ class ImagePut { DllCall("gdiplus\GdipCloneImage", "ptr", pBitmap, "ptr*", &pBitmapClone:=0) DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmapClone) - pTimeProc := RegisterSyncCallback(TimeProc, hwnd) + pTimeProc := RegisterSyncCallback(hwnd, 0x8000) ; Allocate a private struct. ptr := DllCall("GlobalAlloc", "uint", 0, "uptr", 4*A_PtrSize, "ptr") @@ -3265,6 +3239,7 @@ class ImagePut { , "uint", 0 ; fuEvent , "uint") +/* ; Debug code static start := 0, sum := 0, count := 0, sum2 := 0, count2 := 0 @@ -3286,6 +3261,7 @@ class ImagePut { ; "`nFloor and Ceiling:`t" Floor(delay / resolution) * resolution ", " Ceil(delay / resolution) * resolution } start := now +*/ From ee38ebcad88d3e6e2bf63b229321a36a296940d1 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 9 Sep 2023 16:29:10 -0400 Subject: [PATCH 434/492] Use postmessage to kickoff the animation loop --- ImagePut.ahk | 99 +++++++++++++++++++++++++++------------------------- 1 file changed, 51 insertions(+), 48 deletions(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index 0d2c757a..999866e9 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2954,47 +2954,47 @@ class ImagePut { p := pcb if (A_PtrSize = 8) { - /* - 48 89 4c 24 08 ; mov [rsp+8], rcx - 48 89 54'24 10 ; mov [rsp+16], rdx - 4c 89 44 24 18 ; mov [rsp+24], r8 - 4c'89 4c 24 20 ; mov [rsp+32], r9 - 48 83 ec 28' ; sub rsp, 40 - 4c 8d 44 24 30 ; lea r8, [rsp+48] (arg 3, ¶ms) - 49 b9 .. ; mov r9, .. (arg 4, operand to follow) - */ - p := NumPut("ptr" , 0x54894808244c8948, - "ptr" , 0x4c182444894c1024, - "ptr" , 0x28ec834820244c89, - "ptr" , 0x00b9493024448d4c, p) - 1 - lParamPtr := p, p += 8 - - p := NumPut("char" , 0xba, ; mov edx, nmsg - "int" , msg, - "char" , 0xb9, ; mov ecx, hwnd - "int" , hwnd, - "short", 0xb848, ; mov rax, SendMessageW - "ptr" , SendMessageW, + /* + 48 89 4c 24 08 ; mov [rsp+8], rcx + 48 89 54'24 10 ; mov [rsp+16], rdx + 4c 89 44 24 18 ; mov [rsp+24], r8 + 4c'89 4c 24 20 ; mov [rsp+32], r9 + 48 83 ec 28' ; sub rsp, 40 + 4c 8d 44 24 30 ; lea r8, [rsp+48] (arg 3, ¶ms) + 49 b9 .. ; mov r9, .. (arg 4, operand to follow) + */ + p := NumPut("ptr" , 0x54894808244c8948, + "ptr" , 0x4c182444894c1024, + "ptr" , 0x28ec834820244c89, + "ptr" , 0x00b9493024448d4c, p) - 1 + lParamPtr := p, p += 8 + + p := NumPut("char" , 0xba, ; mov edx, nmsg + "int" , msg, + "char" , 0xb9, ; mov ecx, hwnd + "int" , hwnd, + "short", 0xb848, ; mov rax, SendMessageW + "ptr" , SendMessageW, /* ff d0 ; call rax 48 83 c4 28 ; add rsp, 40 c3 ; ret */ - "ptr" , 0x00c328c48348d0ff, p) + "ptr" , 0x00c328c48348d0ff, p) } else { - p := NumPut("char" , 0x68, p) ; push ... (lParam data) - lParamPtr := p, p += 4 - p := NumPut("int" , 0x0824448d, ; lea eax, [esp+8] - "char" , 0x50, ; push eax - "char" , 0x68, ; push nmsg - "int" , msg, - "char" , 0x68, ; push hwnd - "int" , hwnd, - "char" , 0xb8, ; mov eax, &SendMessageW - "int" , SendMessageW, - "short", 0xd0ff, ; call eax - "char" , 0xc2, ; ret argsize - "short", 0, p) ; InStr(Options, "C") ? 0 : ParamCount * 4 + p := NumPut("char" , 0x68, p) ; push ... (lParam data) + lParamPtr := p, p += 4 + p := NumPut("int" , 0x0824448d, ; lea eax, [esp+8] + "char" , 0x50, ; push eax + "char" , 0x68, ; push nmsg + "int" , msg, + "char" , 0x68, ; push hwnd + "int" , hwnd, + "char" , 0xb8, ; mov eax, &SendMessageW + "int" , SendMessageW, + "short", 0xd0ff, ; call eax + "char" , 0xc2, ; ret argsize + "short", 0, p) ; InStr(Options, "C") ? 0 : ParamCount * 4 } NumPut("ptr", p, lParamPtr) return pcb @@ -3023,14 +3023,19 @@ class ImagePut { ; Preserve GDI+ scope. ImagePut.gdiplusStartup() - DllCall("winmm\timeBeginPeriod", "uint", 10) + + DllCall("PostMessage", "ptr", hwnd, "uint", 0x8000, "uptr", 0, "ptr", 0) + /* + + DllCall("winmm\timeSetEvent" , "uint", 1 ; uDelay - , "uint", 10 ; uResolution + , "uint", 1 ; uResolution , "ptr", pTimeProc ; lpTimeProc , "uint", hwnd ; dwUser , "uint", 0 ; fuEvent , "uint") + */ } ; WM_APP - Animate GIFs @@ -3197,11 +3202,9 @@ class ImagePut { return ; Get next frame. - frames := NumGet(Item + 4, "uint") // 4 ; Max frames - ;frame += 1 ; Next frame - frame := mod(frame + 1, frames) ; Loop back to first frame - NumPut("int", frame, ptr, 0*A_PtrSize) - + frames := NumGet(Item + 4, "uint") // 4 ; Total number of frames + frame := mod(frame + 1, frames) ; Get next frame; loop back to 0 + NumPut("int", frame, ptr, 0*A_PtrSize) ; Save the frame number ; Get delay. delays := NumGet(Item + 8 + A_PtrSize, "ptr") ; Array of delays @@ -3232,14 +3235,14 @@ class ImagePut { DllCall("winmm\timeKillEvent", "uint", wparam) ; Kill previous timer r := DllCall("winmm\timeSetEvent" - , "uint", delay-3.1 ; uDelay - , "uint", 1 ; uResolution + , "uint", delay ; uDelay + , "uint", 1 ; uResolution , "ptr", pTimeProc ; lpTimeProc , "uint", hwnd ; dwUser , "uint", 0 ; fuEvent , "uint") -/* + ; Debug code static start := 0, sum := 0, count := 0, sum2 := 0, count2 := 0 @@ -3250,9 +3253,9 @@ class ImagePut { sum += time count++ average := sum / count - sum2 += delay-3.1 ; change this to res or delay + sum2 += delay ; change this to res or delay count2++ - if count > 1000 + ;if count > 1000 Tooltip "Current Tick:`t" Round(time, 4) . "`nAverage FPS:`t" Round(average, 4) . "`nQueued FPS:`t" Round(sum2 / count2, 4) @@ -3261,7 +3264,7 @@ class ImagePut { ; "`nFloor and Ceiling:`t" Floor(delay / resolution) * resolution ", " Ceil(delay / resolution) * resolution } start := now -*/ + From d9c6e62292eb1345bfda55e0a4147dc01c33963a Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 11 Sep 2023 03:27:26 -0400 Subject: [PATCH 435/492] Use a periodic timer to avoid timer init delay --- ImagePut.ahk | 161 +++++++++++++++++++-------------------------------- 1 file changed, 60 insertions(+), 101 deletions(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index 999866e9..c065c6eb 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2945,41 +2945,42 @@ class ImagePut { DllCall("gdiplus\GdipImageGetFrameCount", "ptr", pBitmap, "ptr", dimIDs, "uint*", &frames:=0) - static RegisterSyncCallback(hwnd, msg) { + + static SyncWindowProc(hwnd, msg, paramCount := 0) { hModule := DllCall("GetModuleHandle", "str", "user32.dll", "ptr") SendMessageW := DllCall("GetProcAddress", "ptr", hModule, "astr", "SendMessageW", "ptr") pcb := DllCall("GlobalAlloc", "uint", 0, "ptr", 96, "ptr") DllCall("VirtualProtect", "ptr", pcb, "ptr", 96, "uint", 0x40, "uint*", 0) - + p := pcb if (A_PtrSize = 8) { - /* - 48 89 4c 24 08 ; mov [rsp+8], rcx - 48 89 54'24 10 ; mov [rsp+16], rdx - 4c 89 44 24 18 ; mov [rsp+24], r8 - 4c'89 4c 24 20 ; mov [rsp+32], r9 - 48 83 ec 28' ; sub rsp, 40 - 4c 8d 44 24 30 ; lea r8, [rsp+48] (arg 3, ¶ms) - 49 b9 .. ; mov r9, .. (arg 4, operand to follow) - */ + /* + 48 89 4c 24 08 ; mov [rsp+8], rcx + 48 89 54'24 10 ; mov [rsp+16], rdx + 4c 89 44 24 18 ; mov [rsp+24], r8 + 4c'89 4c 24 20 ; mov [rsp+32], r9 + 48 83 ec 28' ; sub rsp, 40 + 4c 8d 44 24 30 ; lea r8, [rsp+48] (arg 3, ¶ms) + 49 b9 .. ; mov r9, .. (arg 4, operand to follow) + */ p := NumPut("ptr" , 0x54894808244c8948, "ptr" , 0x4c182444894c1024, "ptr" , 0x28ec834820244c89, "ptr" , 0x00b9493024448d4c, p) - 1 lParamPtr := p, p += 8 - + p := NumPut("char" , 0xba, ; mov edx, nmsg - "int" , msg, + "int" , msg, "char" , 0xb9, ; mov ecx, hwnd - "int" , hwnd, + "int" , hwnd, "short", 0xb848, ; mov rax, SendMessageW "ptr" , SendMessageW, - /* - ff d0 ; call rax - 48 83 c4 28 ; add rsp, 40 - c3 ; ret - */ + /* + ff d0 ; call rax + 48 83 c4 28 ; add rsp, 40 + c3 ; ret + */ "ptr" , 0x00c328c48348d0ff, p) } else { p := NumPut("char" , 0x68, p) ; push ... (lParam data) @@ -2987,16 +2988,18 @@ class ImagePut { p := NumPut("int" , 0x0824448d, ; lea eax, [esp+8] "char" , 0x50, ; push eax "char" , 0x68, ; push nmsg - "int" , msg, + "int" , msg, "char" , 0x68, ; push hwnd - "int" , hwnd, + "int" , hwnd, "char" , 0xb8, ; mov eax, &SendMessageW "int" , SendMessageW, "short", 0xd0ff, ; call eax "char" , 0xc2, ; ret argsize - "short", 0, p) ; InStr(Options, "C") ? 0 : ParamCount * 4 + "short", ParamCount*4, p) ; InStr(Options, "C") ? 0 } - NumPut("ptr", p, lParamPtr) + NumPut("ptr", p, lParamPtr) ; To be passed as lParam. + p := NumPut("ptr", 0, p) ; There isn't a function object here so... + p := NumPut("int", ParamCount, lParamPtr) return pcb } @@ -3011,7 +3014,10 @@ class ImagePut { DllCall("gdiplus\GdipCloneImage", "ptr", pBitmap, "ptr*", &pBitmapClone:=0) DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmapClone) - pTimeProc := RegisterSyncCallback(hwnd, 0x8000) + ; Because timeSetEvent calls via a seperate thread, those events can be synchronized + ; with the main thread using a window message. Thanks: Lexikos + ; LPTIMECALLBACK: (uTimerID, uMsg, dwUser, dw1, dw2) + pTimeProc := SyncWindowProc(hwnd, 0x8000, 5) ; ParamCount = 5 ; Allocate a private struct. ptr := DllCall("GlobalAlloc", "uint", 0, "uptr", 4*A_PtrSize, "ptr") @@ -3024,23 +3030,16 @@ class ImagePut { ; Preserve GDI+ scope. ImagePut.gdiplusStartup() - DllCall("PostMessage", "ptr", hwnd, "uint", 0x8000, "uptr", 0, "ptr", 0) - /* - + ; Start GIF Animation loop (without using a timer for now). + ; DllCall("PostMessage", "ptr", hwnd, "uint", 0x8000, "uptr", 0, "ptr", 0) DllCall("winmm\timeSetEvent" - , "uint", 1 ; uDelay - , "uint", 1 ; uResolution - , "ptr", pTimeProc ; lpTimeProc - , "uint", hwnd ; dwUser - , "uint", 0 ; fuEvent - , "uint") - */ - } - - ; WM_APP - Animate GIFs - static TimeProc(uTimerID, uMsg, hwnd, dw1, dw2) { - DllCall("PostMessage", "ptr", hwnd, "uint", 0x8000, "uptr", uTimerID, "ptr", 0) + , "uint", 10 ; uDelay + , "uint", 10 ; uResolution + , "ptr", pTimeProc ; lpTimeProc + , "uint", hwnd ; dwUser + , "uint", 1 ; fuEvent + , "uint") } return hwnd @@ -3181,10 +3180,7 @@ class ImagePut { SetTimer (tock => (tick == tock) && Tooltip()).Bind(A_TickCount), -7000 } - - - - + ; WM_APP - Animate GIFs if (uMsg = 0x8000) { ; Thanks tmplinshi, Teadrinker - https://www.autohotkey.com/boards/viewtopic.php?f=76&t=83358 Critical @@ -3197,79 +3193,45 @@ class ImagePut { , Item := NumGet(ptr, 2*A_PtrSize, "ptr") , pTimeProc := NumGet(ptr, 3*A_PtrSize, "ptr") - ; Exit loop. + ; Exit GIF animation loop. if !pBitmap return - ; Get next frame. - frames := NumGet(Item + 4, "uint") // 4 ; Total number of frames - frame := mod(frame + 1, frames) ; Get next frame; loop back to 0 - NumPut("int", frame, ptr, 0*A_PtrSize) ; Save the frame number - ; Get delay. - delays := NumGet(Item + 8 + A_PtrSize, "ptr") ; Array of delays - delay := 10 * NumGet(delays + 4*frame, "uint") ; Delay of next frame - delay := max(delay, 10) ; Minimum delay is 10ms - (delay == 10) && delay := 100 ; 10 ms is actually 100 ms + delays := NumGet(Item + 8 + A_PtrSize, "ptr") ; Array of delays + delay := 10 * NumGet(delays + 4*frame, "uint") ; Delay of next frame + delay := max(delay, 10) ; Minimum delay is 10ms + (delay == 10) && delay := 100 ; 10 ms is actually 100 ms ; See: https://www.biphelps.com/blog/The-Fastest-GIF-Does-Not-Exist - + static current := 0 + current += 10 ; Add resolution of timer. + if ! (abs(current - delay) <= 5) + return /* - ; Randomize the delay in intervals of 15.6 - resolution := 15.6 - rand := random() - percentage := mod(delay, resolution) / resolution - percentage *= 0.957 ; Higher is faster, lower is slower - - ; Randomized multiples of resolution - if (rand > percentage) - res := Floor(delay / resolution) * resolution - else - res := Ceil(delay / resolution) * resolution -*/ - ; Async the next frame as soon as possible to prevent rendering lag. - ;SetTimer WindowProc.bind(hwnd, uMsg, 0, 0), -1 * delay - - - DllCall("winmm\timeKillEvent", "uint", wparam) ; Kill previous timer - - r := DllCall("winmm\timeSetEvent" - , "uint", delay ; uDelay - , "uint", 1 ; uResolution - , "ptr", pTimeProc ; lpTimeProc - , "uint", hwnd ; dwUser - , "uint", 0 ; fuEvent - , "uint") - - - ; Debug code - static start := 0, sum := 0, count := 0, sum2 := 0, count2 := 0 + static start := 0, sum := 0, count := 1 DllCall("QueryPerformanceFrequency", "int64*", &frequency:=0) DllCall("QueryPerformanceCounter", "int64*", &now:=0) time := (now - start) / frequency * 1000 if (time < 10000) { sum += time - count++ - average := sum / count - sum2 += delay ; change this to res or delay - count2++ - ;if count > 1000 - Tooltip "Current Tick:`t" Round(time, 4) - . "`nAverage FPS:`t" Round(average, 4) - . "`nQueued FPS:`t" Round(sum2 / count2, 4) - . "`nTarget FPS:`t" delay - ; "`nPercentage:`t" percentage ", " rand - ; "`nFloor and Ceiling:`t" Floor(delay / resolution) * resolution ", " Ceil(delay / resolution) * resolution + count += 1 + if (mod(count, 10) = 0) ; Prevent the tooltip from impacting timings + Tooltip "Current Delay:`t" Round(time, 4) + . "`nAverage Delay:`t" Round(sum / count, 4) + . "`nPlanned Delay:`t" (delay ?? "unknown") } start := now + */ + current := 0 - - - - + ; Get next frame. + frames := NumGet(Item + 4, "uint") // 4 ; Total number of frames + frame := mod(frame + 1, frames) ; Get next frame; loop back to 0 + NumPut("int", frame, ptr, 0*A_PtrSize) ; Save the frame number ; Select frame to show. DllCall("gdiplus\GdipImageGetFrameDimensionsCount", "ptr", pBitmap, "uint*", &dims:=0) @@ -3312,11 +3274,8 @@ class ImagePut { , "uint", 0 ; crKey , "uint*", 0xFF << 16 | 0x01 << 24 ; *pblend , "uint", 2) ; dwFlags - } - - ; Must return default: return DllCall("DefWindowProc", "ptr", hwnd, "uint", uMsg, "uptr", wParam, "ptr", lParam, "ptr") From 3cfd06950f5963b3b0a9c19e490e6f2434b287af Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Mon, 11 Sep 2023 04:09:40 -0400 Subject: [PATCH 436/492] Fix multiple GIFs not playing at the same time --- ImagePut.ahk | 215 +++++++++++++++++++++++++++------------------------ 1 file changed, 115 insertions(+), 100 deletions(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index c065c6eb..dba914c0 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2944,65 +2944,6 @@ class ImagePut { DllCall("gdiplus\GdipImageGetFrameDimensionsList", "ptr", pBitmap, "ptr", dimIDs := Buffer(16*dims), "uint", dims) DllCall("gdiplus\GdipImageGetFrameCount", "ptr", pBitmap, "ptr", dimIDs, "uint*", &frames:=0) - - - static SyncWindowProc(hwnd, msg, paramCount := 0) { - hModule := DllCall("GetModuleHandle", "str", "user32.dll", "ptr") - SendMessageW := DllCall("GetProcAddress", "ptr", hModule, "astr", "SendMessageW", "ptr") - - pcb := DllCall("GlobalAlloc", "uint", 0, "ptr", 96, "ptr") - DllCall("VirtualProtect", "ptr", pcb, "ptr", 96, "uint", 0x40, "uint*", 0) - - p := pcb - if (A_PtrSize = 8) { - /* - 48 89 4c 24 08 ; mov [rsp+8], rcx - 48 89 54'24 10 ; mov [rsp+16], rdx - 4c 89 44 24 18 ; mov [rsp+24], r8 - 4c'89 4c 24 20 ; mov [rsp+32], r9 - 48 83 ec 28' ; sub rsp, 40 - 4c 8d 44 24 30 ; lea r8, [rsp+48] (arg 3, ¶ms) - 49 b9 .. ; mov r9, .. (arg 4, operand to follow) - */ - p := NumPut("ptr" , 0x54894808244c8948, - "ptr" , 0x4c182444894c1024, - "ptr" , 0x28ec834820244c89, - "ptr" , 0x00b9493024448d4c, p) - 1 - lParamPtr := p, p += 8 - - p := NumPut("char" , 0xba, ; mov edx, nmsg - "int" , msg, - "char" , 0xb9, ; mov ecx, hwnd - "int" , hwnd, - "short", 0xb848, ; mov rax, SendMessageW - "ptr" , SendMessageW, - /* - ff d0 ; call rax - 48 83 c4 28 ; add rsp, 40 - c3 ; ret - */ - "ptr" , 0x00c328c48348d0ff, p) - } else { - p := NumPut("char" , 0x68, p) ; push ... (lParam data) - lParamPtr := p, p += 4 - p := NumPut("int" , 0x0824448d, ; lea eax, [esp+8] - "char" , 0x50, ; push eax - "char" , 0x68, ; push nmsg - "int" , msg, - "char" , 0x68, ; push hwnd - "int" , hwnd, - "char" , 0xb8, ; mov eax, &SendMessageW - "int" , SendMessageW, - "short", 0xd0ff, ; call eax - "char" , 0xc2, ; ret argsize - "short", ParamCount*4, p) ; InStr(Options, "C") ? 0 - } - NumPut("ptr", p, lParamPtr) ; To be passed as lParam. - p := NumPut("ptr", 0, p) ; There isn't a function object here so... - p := NumPut("int", ParamCount, lParamPtr) - return pcb - } - ; GIF Animations! if (frames > 1) { ; Save frame delays because they are slow enough to impact timing. @@ -3014,37 +2955,94 @@ class ImagePut { DllCall("gdiplus\GdipCloneImage", "ptr", pBitmap, "ptr*", &pBitmapClone:=0) DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmapClone) - ; Because timeSetEvent calls via a seperate thread, those events can be synchronized - ; with the main thread using a window message. Thanks: Lexikos + ; Because timeSetEvent calls in a seperate thread, redirect to main thread. ; LPTIMECALLBACK: (uTimerID, uMsg, dwUser, dw1, dw2) - pTimeProc := SyncWindowProc(hwnd, 0x8000, 5) ; ParamCount = 5 + pTimeProc := this.SyncWindowProc(hwnd, 0x8000, 5) ; ParamCount = 5 ; Allocate a private struct. - ptr := DllCall("GlobalAlloc", "uint", 0, "uptr", 4*A_PtrSize, "ptr") - NumPut("int", -1, ptr, 0*A_PtrSize) ; current frame - NumPut("ptr", pBitmapClone, ptr, 1*A_PtrSize) ; rest of GIF frames - NumPut("ptr", Item, ptr, 2*A_PtrSize) ; frame delays - NumPut("ptr", pTimeProc, ptr, 3*A_PtrSize) ; timer callback + ptr := DllCall("GlobalAlloc", "uint", 0, "uptr", 6*A_PtrSize, "ptr") + NumPut("int", 32, ptr, 0*A_PtrSize) ; custom struct id + NumPut("int", -1, ptr, 1*A_PtrSize) ; frame number + NumPut("int", 0, ptr, 2*A_PtrSize) ; current delay + NumPut("ptr", pBitmapClone, ptr, 3*A_PtrSize) ; GIF storage + NumPut("ptr", Item, ptr, 4*A_PtrSize) ; Item (max frames & delays) + NumPut("ptr", pTimeProc, ptr, 5*A_PtrSize) ; callback address DllCall("SetWindowLong", "ptr", hwnd, "int", 3*A_PtrSize, "ptr", ptr) ; Preserve GDI+ scope. ImagePut.gdiplusStartup() - ; Start GIF Animation loop (without using a timer for now). - ; DllCall("PostMessage", "ptr", hwnd, "uint", 0x8000, "uptr", 0, "ptr", 0) - - DllCall("winmm\timeSetEvent" - , "uint", 10 ; uDelay - , "uint", 10 ; uResolution - , "ptr", pTimeProc ; lpTimeProc - , "uint", hwnd ; dwUser - , "uint", 1 ; fuEvent - , "uint") + ; Start GIF Animation loop. + timer := DllCall("winmm\timeSetEvent" + , "uint", 10 ; uDelay + , "uint", 10 ; uResolution + , "ptr", pTimeProc ; lpTimeProc + , "uint", hwnd ; dwUser + , "uint", 1 ; fuEvent + , "uint") + DllCall("SetWindowLong", "ptr", hwnd, "int", 4*A_PtrSize, "ptr", timer) } return hwnd } + static SyncWindowProc(hwnd, msg, paramCount := 0) { + hModule := DllCall("GetModuleHandle", "str", "user32.dll", "ptr") + SendMessageW := DllCall("GetProcAddress", "ptr", hModule, "astr", "SendMessageW", "ptr") + + pcb := DllCall("GlobalAlloc", "uint", 0, "ptr", 96, "ptr") + DllCall("VirtualProtect", "ptr", pcb, "ptr", 96, "uint", 0x40, "uint*", 0) + + p := pcb + if (A_PtrSize = 8) { + /* + 48 89 4c 24 08 ; mov [rsp+8], rcx + 48 89 54'24 10 ; mov [rsp+16], rdx + 4c 89 44 24 18 ; mov [rsp+24], r8 + 4c'89 4c 24 20 ; mov [rsp+32], r9 + 48 83 ec 28' ; sub rsp, 40 + 4c 8d 44 24 30 ; lea r8, [rsp+48] (arg 3, ¶ms) + 49 b9 .. ; mov r9, .. (arg 4, operand to follow) + */ + p := NumPut("ptr" , 0x54894808244c8948, + "ptr" , 0x4c182444894c1024, + "ptr" , 0x28ec834820244c89, + "ptr" , 0x00b9493024448d4c, p) - 1 + lParamPtr := p, p += 8 + + p := NumPut("char" , 0xba, ; mov edx, nmsg + "int" , msg, + "char" , 0xb9, ; mov ecx, hwnd + "int" , hwnd, + "short", 0xb848, ; mov rax, SendMessageW + "ptr" , SendMessageW, + /* + ff d0 ; call rax + 48 83 c4 28 ; add rsp, 40 + c3 ; ret + */ + "ptr" , 0x00c328c48348d0ff, p) + } else { + p := NumPut("char" , 0x68, p) ; push ... (lParam data) + lParamPtr := p, p += 4 + p := NumPut("int" , 0x0824448d, ; lea eax, [esp+8] + "char" , 0x50, ; push eax + "char" , 0x68, ; push nmsg + "int" , msg, + "char" , 0x68, ; push hwnd + "int" , hwnd, + "char" , 0xb8, ; mov eax, &SendMessageW + "int" , SendMessageW, + "short", 0xd0ff, ; call eax + "char" , 0xc2, ; ret argsize + "short", ParamCount*4, p) ; InStr(Options, "C") ? 0 + } + NumPut("ptr", p, lParamPtr) ; To be passed as lParam. + p := NumPut("ptr", 0, p) ; There isn't a function object here so... + p := NumPut("int", ParamCount, lParamPtr) + return pcb + } + static WindowClass(style := 0) { ; The window class shares the name of this class. cls := this.prototype.__class @@ -3101,17 +3099,28 @@ class ImagePut { DllCall("DeleteObject", "ptr", hbm) DllCall("DeleteDC", "ptr", hdc) - ; Exit GIF Animation loop. - if pBitmap := DllCall("GetWindowLong", "ptr", hwnd, "int", 3*A_PtrSize, "ptr") { - DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) - DllCall("SetWindowLong", "ptr", hwnd, "int", 3*A_PtrSize, "ptr", 0) ; Exit loop + if ptr := DllCall("GetWindowLong", "ptr", hwnd, "int", 3*A_PtrSize, "ptr") { + id := NumGet(ptr, 0, "int") + + ; Exit GIF Animation loop. + if (id == 32) { + pBitmap := NumGet(ptr, 3*A_PtrSize, "ptr") + Item := NumGet(ptr, 4*A_PtrSize, "ptr") + pTimeProc := NumGet(ptr, 5*A_PtrSize, "ptr") + timer := DllCall("GetWindowLong", "ptr", hwnd, "int", 4*A_PtrSize, "ptr") - ; Delete Item. - Item := DllCall("GetWindowLong", "ptr", hwnd, "int", 4*A_PtrSize, "ptr") - DllCall("GlobalFree", "ptr", Item) + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + DllCall("GlobalFree", "ptr", Item) + DllCall("GlobalFree", "ptr", pTimeProc) + DllCall("winmm\timeKillEvent", "uint", timer) - ; Exit GDI+ conditionally due to the ImagePut class being destroyed first. - ImagePut.gdiplusShutdown() + ; Exit GDI+ conditionally due to the ImagePut class being destroyed first. + ImagePut.gdiplusShutdown() + + ; Exit the window procedure. + DllCall("GlobalFree", "ptr", ptr) + DllCall("SetWindowLong", "ptr", hwnd, "int", 3*A_PtrSize, "ptr", 0) ; Exit loop + } } Persistent(--active_windows) @@ -3188,15 +3197,21 @@ class ImagePut { ; Get variables. hdc := DllCall("GetWindowLong", "ptr", hwnd, "int", 2*A_PtrSize, "ptr") ptr := DllCall("GetWindowLong", "ptr", hwnd, "int", 3*A_PtrSize, "ptr") - , frame := NumGet(ptr, 0*A_PtrSize, "int") - , pBitmap := NumGet(ptr, 1*A_PtrSize, "ptr") - , Item := NumGet(ptr, 2*A_PtrSize, "ptr") - , pTimeProc := NumGet(ptr, 3*A_PtrSize, "ptr") ; Exit GIF animation loop. - if !pBitmap + if !ptr return + frame := NumGet(ptr, 1*A_PtrSize, "int") + current := NumGet(ptr, 2*A_PtrSize, "int") + pBitmap := NumGet(ptr, 3*A_PtrSize, "ptr") + Item := NumGet(ptr, 4*A_PtrSize, "ptr") + pTimeProc := NumGet(ptr, 5*A_PtrSize, "ptr") + + ; Get next frame. + frames := NumGet(Item + 4, "uint") // 4 ; Total number of frames + frame := mod(frame + 1, frames) ; Loop back to zero + ; Get delay. delays := NumGet(Item + 8 + A_PtrSize, "ptr") ; Array of delays delay := 10 * NumGet(delays + 4*frame, "uint") ; Delay of next frame @@ -3204,11 +3219,18 @@ class ImagePut { (delay == 10) && delay := 100 ; 10 ms is actually 100 ms ; See: https://www.biphelps.com/blog/The-Fastest-GIF-Does-Not-Exist - static current := 0 - current += 10 ; Add resolution of timer. + ; Check delay. + current += 10 ; Add resolution of timer + NumPut("int", current, ptr, 2*A_PtrSize) ; Save the current delay + + ; Note that the rounding errors may accumulate, but it will even out over time. + ; This checks every 10 ms. Using <= 5 ensures that the range will always be 10 ms. if ! (abs(current - delay) <= 5) return + NumPut("int", frame, ptr, 1*A_PtrSize) ; Save the frame number + NumPut("int", 0, ptr, 2*A_PtrSize) ; Reset the current delay + /* ; Debug code static start := 0, sum := 0, count := 1 @@ -3226,13 +3248,6 @@ class ImagePut { start := now */ - current := 0 - - ; Get next frame. - frames := NumGet(Item + 4, "uint") // 4 ; Total number of frames - frame := mod(frame + 1, frames) ; Get next frame; loop back to 0 - NumPut("int", frame, ptr, 0*A_PtrSize) ; Save the frame number - ; Select frame to show. DllCall("gdiplus\GdipImageGetFrameDimensionsCount", "ptr", pBitmap, "uint*", &dims:=0) DllCall("gdiplus\GdipImageGetFrameDimensionsList", "ptr", pBitmap, "ptr", dimIDs := Buffer(16*dims), "uint", dims) From 7ee795aff11bbe84906afbcd8c0526087caf3a8a Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 12 Sep 2023 12:03:14 -0400 Subject: [PATCH 437/492] sync v1 / v2 compatibility --- ImagePut (for v1).ahk | 200 +++++++++++++++++++++++++++++------------- ImagePut.ahk | 68 +++++++------- 2 files changed, 178 insertions(+), 90 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 320d4099..5130139a 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2796,7 +2796,7 @@ class ImagePut { DllCall("SetWindowLong", "ptr", child, "int", 0*A_PtrSize, "ptr", hwnd) ; parent window DllCall("SetWindowLong", "ptr", child, "int", 1*A_PtrSize, "ptr", child) ; child window - ; Prevent empty windows from showing. + ; Delaying this call prevents empty window borders from appearing. DllCall("ShowWindow", "ptr", hwnd, "int", 1) return hwnd @@ -2955,20 +2955,94 @@ class ImagePut { DllCall("gdiplus\GdipCloneImage", "ptr", pBitmap, "ptr*", pBitmapClone:=0) DllCall("gdiplus\GdipImageForceValidation", "ptr", pBitmapClone) + ; Because timeSetEvent calls in a seperate thread, redirect to main thread. + ; LPTIMECALLBACK: (uTimerID, uMsg, dwUser, dw1, dw2) + pTimeProc := this.SyncWindowProc(hwnd, 0x8000, 5) ; ParamCount = 5 + ; Store extra data inside window struct (cbWndExtra). - DllCall("SetWindowLong", "ptr", hwnd, "int", 3*A_PtrSize, "ptr", pBitmapClone) - DllCall("SetWindowLong", "ptr", hwnd, "int", 4*A_PtrSize, "ptr", Item) + ptr := DllCall("GlobalAlloc", "uint", 0, "uptr", 6*A_PtrSize, "ptr") + NumPut( 32, ptr + 0*A_PtrSize, "int") ; custom struct id + NumPut( -1, ptr + 1*A_PtrSize, "int") ; frame number + NumPut( 0, ptr + 2*A_PtrSize, "int") ; current delay + NumPut(pBitmapClone, ptr + 3*A_PtrSize, "ptr") ; GIF storage + NumPut( Item, ptr + 4*A_PtrSize, "ptr") ; Item (max frames & delays) + NumPut( pTimeProc, ptr + 5*A_PtrSize, "ptr") ; callback address + DllCall("SetWindowLong", "ptr", hwnd, "int", 3*A_PtrSize, "ptr", ptr) ; Preserve GDI+ scope. ImagePut.gdiplusStartup() - ; Start animations using WM_APP in WindowProc(). - DllCall("PostMessage", "ptr", hwnd, "uint", 0x8000, "uptr", -1, "ptr", 0) + ; Start GIF Animation loop. + timer := DllCall("winmm\timeSetEvent" + , "uint", 10 ; uDelay + , "uint", 10 ; uResolution + , "ptr", pTimeProc ; lpTimeProc + , "uint", 0 ; dwUser + , "uint", 1 ; fuEvent + , "uint") + DllCall("SetWindowLong", "ptr", hwnd, "int", 4*A_PtrSize, "ptr", timer) } return hwnd } + SyncWindowProc(hwnd, msg, ParamCount := 0) { + hModule := DllCall("GetModuleHandle", "str", "user32.dll", "ptr") + SendMessageW := DllCall("GetProcAddress", "ptr", hModule, "astr", "SendMessageW", "ptr") + + pcb := DllCall("GlobalAlloc", "uint", 0, "ptr", 96, "ptr") + DllCall("VirtualProtect", "ptr", pcb, "ptr", 96, "uint", 0x40, "uint*", 0) + + p := pcb + if (A_PtrSize = 8) { + /* + 48 89 4c 24 08 ; mov [rsp+8], rcx + 48 89 54'24 10 ; mov [rsp+16], rdx + 4c 89 44 24 18 ; mov [rsp+24], r8 + 4c'89 4c 24 20 ; mov [rsp+32], r9 + 48 83 ec 28' ; sub rsp, 40 + 4c 8d 44 24 30 ; lea r8, [rsp+48] (arg 3, ¶ms) + 49 b9 .. ; mov r9, .. (arg 4, operand to follow) + */ + p := NumPut(0x54894808244c8948, p+0) + p := NumPut(0x4c182444894c1024, p+0) + p := NumPut(0x28ec834820244c89, p+0) + p := NumPut( 0xb9493024448d4c, p+0) - 1 + lParamPtr := p, p += 8 + + p := NumPut(0xba, p+0, "char") ; mov edx, nmsg + p := NumPut(msg, p+0, "int") + p := NumPut(0xb9, p+0, "char") ; mov ecx, hwnd + p := NumPut(hwnd, p+0, "int") + p := NumPut(0xb848, p+0, "short") ; mov rax, SendMessageW + p := NumPut(SendMessageW, p+0) + /* + ff d0 ; call rax + 48 83 c4 28 ; add rsp, 40 + c3 ; ret + */ + p := NumPut(0x00c328c48348d0ff, p+0) + } else { + p := NumPut(0x68, p+0, "char") ; push ... (lParam data) + lParamPtr := p, p += 4 + p := NumPut(0x0824448d, p+0, "int") ; lea eax, [esp+8] + p := NumPut(0x50, p+0, "char") ; push eax + p := NumPut(0x68, p+0, "char") ; push nmsg + p := NumPut(msg, p+0, "int") + p := NumPut(0x68, p+0, "char") ; push hwnd + p := NumPut(hwnd, p+0, "int") + p := NumPut(0xb8, p+0, "char") ; mov eax, &SendMessageW + p := NumPut(SendMessageW, p+0, "int") + p := NumPut(0xd0ff, p+0, "short") ; call eax + p := NumPut(0xc2, p+0, "char") ; ret argsize + p := NumPut(ParamCount*4, p+0, "short") ; InStr(Options, "C") ? 0 + } + NumPut(p, lParamPtr+0) ; To be passed as lParam. + p := NumPut(0, p+0) ; There isn't a function object here so... + p := NumPut(ParamCount, p+0, "int") + return pcb + } + WindowClass(style := 0) { ; The window class shares the name of this class. cls := this.__class @@ -3025,17 +3099,28 @@ class ImagePut { DllCall("DeleteObject", "ptr", hbm) DllCall("DeleteDC", "ptr", hdc) - ; Exit GIF Animation loop. - if pBitmap := DllCall("GetWindowLong", "ptr", hwnd, "int", 3*A_PtrSize, "ptr") { - DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) - DllCall("SetWindowLong", "ptr", hwnd, "int", 3*A_PtrSize, "ptr", 0) ; Exit loop + if ptr := DllCall("GetWindowLong", "ptr", hwnd, "int", 3*A_PtrSize, "ptr") { + id := NumGet(ptr, 0, "int") + + ; Exit GIF Animation loop. + if (id == 32) { + pBitmap := NumGet(ptr + 3*A_PtrSize, "ptr") + Item := NumGet(ptr + 4*A_PtrSize, "ptr") + pTimeProc := NumGet(ptr + 5*A_PtrSize, "ptr") + timer := DllCall("GetWindowLong", "ptr", hwnd, "int", 4*A_PtrSize, "ptr") - ; Delete Item. - Item := DllCall("GetWindowLong", "ptr", hwnd, "int", 4*A_PtrSize, "ptr") - DllCall("GlobalFree", "ptr", Item) + DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) + DllCall("GlobalFree", "ptr", Item) + DllCall("GlobalFree", "ptr", pTimeProc) + DllCall("winmm\timeKillEvent", "uint", timer) - ; Exit GDI+ conditionally due to the ImagePut class being destroyed first. - ImagePut.gdiplusShutdown() + ; Exit GDI+ conditionally due to the ImagePut class being destroyed first. + ImagePut.gdiplusShutdown() + + ; Exit the window procedure. + DllCall("GlobalFree", "ptr", ptr) + DllCall("SetWindowLong", "ptr", hwnd, "int", 3*A_PtrSize, "ptr", 0) ; Exit loop + } } Hotkey % "^+F12", % void, Off ; Cannot disable script persistence, does nothing @@ -3102,14 +3187,15 @@ class ImagePut { static tick tick := A_TickCount pWndProc := RegisterCallback(ImagePut.WindowProc,,, &ImagePut) - clock := Func("DllCall").bind(pWndProc, "ptr", hwnd, "uint", 0x8001, "uptr", A_TickCount, "ptr", 0) + clock := Func("DllCall").bind(pWndProc, "ptr", hwnd, "uint", 0x8001, "uptr", A_TickCount, "ptr", pWndProc) SetTimer % clock, -7000 - ;DllCall("GlobalFree", "ptr", pWndProc, "ptr") } if (uMsg = 0x8001) - if (tick == wParam) + if (tick == wParam) { ; tock is wParam Tooltip + DllCall("GlobalFree", "ptr", lParam, "ptr") ; pWndProc is lParam + } ; WM_APP - Animate GIFs if (uMsg = 0x8000) { @@ -3118,63 +3204,58 @@ class ImagePut { ; Get variables. hdc := DllCall("GetWindowLong", "ptr", hwnd, "int", 2*A_PtrSize, "ptr") - pBitmap := DllCall("GetWindowLong", "ptr", hwnd, "int", 3*A_PtrSize, "ptr") - Item := DllCall("GetWindowLong", "ptr", hwnd, "int", 4*A_PtrSize, "ptr") + ptr := DllCall("GetWindowLong", "ptr", hwnd, "int", 3*A_PtrSize, "ptr") - ; Exit loop. - if !pBitmap + ; Exit GIF animation loop. + if !ptr return + frame := NumGet(ptr + 1*A_PtrSize, "int") + current := NumGet(ptr + 2*A_PtrSize, "int") + pBitmap := NumGet(ptr + 3*A_PtrSize, "ptr") + Item := NumGet(ptr + 4*A_PtrSize, "ptr") + pTimeProc := NumGet(ptr + 5*A_PtrSize, "ptr") + ; Get next frame. - frames := NumGet(Item + 4, "uint") // 4 ; Max frames - frame := wParam + 1 ; Next frame - frame := mod(frame, frames) ; Loop back to first frame - - ; Get delay. - delays := NumGet(Item + 8 + A_PtrSize, "ptr") ; Array of delays - delay := 10 * NumGet(delays + 4*frame, "uint") ; Delay of next frame - delay := max(delay, 10) ; Minimum delay is 10ms - (delay == 10) && delay := 100 ; 10 ms is actually 100 ms - ; See: https://www.biphelps.com/blog/The-Fastest-GIF-Does-Not-Exist - - ; Randomize the delay in intervals of 15.6 - resolution := 15.6 - Random rand, 1, 100000 - percentage := mod(delay, resolution) / resolution - percentage *= 0.957 ; Higher is faster, lower is slower - - ; Randomized multiples of resolution - if ((rand := rand / 100000) > percentage) - res := Floor(delay / resolution) * resolution - else - res := Ceil(delay / resolution) * resolution - - ; Async the next frame as soon as possible to prevent rendering lag. - pWndProc := RegisterCallback(ImagePut.WindowProc,,, &ImagePut) - next_frame := Func("DllCall").bind(pWndProc, "ptr", hwnd, "uint", uMsg, "uptr", frame, "ptr", 0) - SetTimer % next_frame, % -1 * res - ; DllCall("GlobalFree", "ptr", pWndProc, "ptr") + frames := NumGet(Item + 4, "uint") // 4 ; Total number of frames + frame := mod(frame + 1, frames) ; Loop back to zero + + ; Get delay. See: https://www.biphelps.com/blog/The-Fastest-GIF-Does-Not-Exist + delays := NumGet(Item + 8 + A_PtrSize, "ptr") ; Array of delays + delay := 10 * NumGet(delays + 4*frame, "uint") ; Delay of next frame + delay := max(delay, 10) ; Minimum delay is 10ms + (delay == 10) && delay := 100 ; 10 ms is actually 100 ms + + ; Check delay. + current += 10 ; Add resolution of timer + NumPut(current, ptr + 2*A_PtrSize, "int") ; Save the current delay + + ; Note that the rounding errors may accumulate, but it will even out over time. + ; This checks every 10 ms. Using <= 5 ensures that the range will always be 10 ms. + ; Will execute by frame number rather than timing, due to the current delay being incremented by 10. + if ! (abs(current - delay) <= 5) + return + + NumPut( frame, ptr + 1*A_PtrSize, "int") ; Save the frame number + NumPut( 0, ptr + 2*A_PtrSize, "int") ; Reset the current delay + /* ; Debug code - static start := 0, sum := 0, count := 0, sum2 := 0, count2 := 0 + static start := 0, sum := 0, count := 0 DllCall("QueryPerformanceFrequency", "int64*", frequency:=0) DllCall("QueryPerformanceCounter", "int64*", now:=0) time := (now - start) / frequency * 1000 if (time < 10000) { sum += time count++ - average := sum / count - sum2 += res - count2++ - Tooltip % "Current Tick:`t" Round(time, 4) - . "`nAverage FPS:`t" Round(average, 4) - . "`nQueued FPS:`t" Round(sum2 / count2, 4) - . "`nTarget FPS:`t" delay - . "`nPercentage:`t" percentage ", " rand - . "`nFloor and Ceiling:`t" Floor(delay / resolution) * resolution ", " Ceil(delay / resolution) * resolution + ;if (mod(count, 10) = 0) ; Prevent the tooltip from impacting timings + Tooltip % "Current Delay:`t" Round(time, 4) + . "`n" "Average Delay:`t" Round(sum / count, 4) + . "`n" "Planned Delay:`t" (delay ? delay : "unknown") } start := now */ + ; Select frame to show. DllCall("gdiplus\GdipImageGetFrameDimensionsCount", "ptr", pBitmap, "uint*", dims:=0) DllCall("gdiplus\GdipImageGetFrameDimensionsList", "ptr", pBitmap, "ptr", &dimIDs := VarSetCapacity(dimIDs, 16*dims), "uint", dims) @@ -3216,7 +3297,6 @@ class ImagePut { , "uint", 0 ; crKey , "uint*", 0xFF << 16 | 0x01 << 24 ; *pblend , "uint", 2) ; dwFlags - return } ; Must return diff --git a/ImagePut.ahk b/ImagePut.ahk index dba914c0..bf3252f4 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2959,14 +2959,14 @@ class ImagePut { ; LPTIMECALLBACK: (uTimerID, uMsg, dwUser, dw1, dw2) pTimeProc := this.SyncWindowProc(hwnd, 0x8000, 5) ; ParamCount = 5 - ; Allocate a private struct. + ; Store extra data inside window struct (cbWndExtra). ptr := DllCall("GlobalAlloc", "uint", 0, "uptr", 6*A_PtrSize, "ptr") - NumPut("int", 32, ptr, 0*A_PtrSize) ; custom struct id - NumPut("int", -1, ptr, 1*A_PtrSize) ; frame number - NumPut("int", 0, ptr, 2*A_PtrSize) ; current delay - NumPut("ptr", pBitmapClone, ptr, 3*A_PtrSize) ; GIF storage - NumPut("ptr", Item, ptr, 4*A_PtrSize) ; Item (max frames & delays) - NumPut("ptr", pTimeProc, ptr, 5*A_PtrSize) ; callback address + NumPut("int", 32, ptr + 0*A_PtrSize) ; custom struct id + NumPut("int", -1, ptr + 1*A_PtrSize) ; frame number + NumPut("int", 0, ptr + 2*A_PtrSize) ; current delay + NumPut("ptr", pBitmapClone, ptr + 3*A_PtrSize) ; GIF storage + NumPut("ptr", Item, ptr + 4*A_PtrSize) ; Item (max frames & delays) + NumPut("ptr", pTimeProc, ptr + 5*A_PtrSize) ; callback address DllCall("SetWindowLong", "ptr", hwnd, "int", 3*A_PtrSize, "ptr", ptr) ; Preserve GDI+ scope. @@ -2977,7 +2977,7 @@ class ImagePut { , "uint", 10 ; uDelay , "uint", 10 ; uResolution , "ptr", pTimeProc ; lpTimeProc - , "uint", hwnd ; dwUser + , "uint", 0 ; dwUser , "uint", 1 ; fuEvent , "uint") DllCall("SetWindowLong", "ptr", hwnd, "int", 4*A_PtrSize, "ptr", timer) @@ -2986,7 +2986,7 @@ class ImagePut { return hwnd } - static SyncWindowProc(hwnd, msg, paramCount := 0) { + static SyncWindowProc(hwnd, msg, ParamCount := 0) { hModule := DllCall("GetModuleHandle", "str", "user32.dll", "ptr") SendMessageW := DllCall("GetProcAddress", "ptr", hModule, "astr", "SendMessageW", "ptr") @@ -3039,7 +3039,7 @@ class ImagePut { } NumPut("ptr", p, lParamPtr) ; To be passed as lParam. p := NumPut("ptr", 0, p) ; There isn't a function object here so... - p := NumPut("int", ParamCount, lParamPtr) + p := NumPut("int", ParamCount, p) return pcb } @@ -3104,9 +3104,9 @@ class ImagePut { ; Exit GIF Animation loop. if (id == 32) { - pBitmap := NumGet(ptr, 3*A_PtrSize, "ptr") - Item := NumGet(ptr, 4*A_PtrSize, "ptr") - pTimeProc := NumGet(ptr, 5*A_PtrSize, "ptr") + pBitmap := NumGet(ptr + 3*A_PtrSize, "ptr") + Item := NumGet(ptr + 4*A_PtrSize, "ptr") + pTimeProc := NumGet(ptr + 5*A_PtrSize, "ptr") timer := DllCall("GetWindowLong", "ptr", hwnd, "int", 4*A_PtrSize, "ptr") DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap) @@ -3189,6 +3189,14 @@ class ImagePut { SetTimer (tock => (tick == tock) && Tooltip()).Bind(A_TickCount), -7000 } + + + + + + + + ; WM_APP - Animate GIFs if (uMsg = 0x8000) { ; Thanks tmplinshi, Teadrinker - https://www.autohotkey.com/boards/viewtopic.php?f=76&t=83358 @@ -3202,48 +3210,48 @@ class ImagePut { if !ptr return - frame := NumGet(ptr, 1*A_PtrSize, "int") - current := NumGet(ptr, 2*A_PtrSize, "int") - pBitmap := NumGet(ptr, 3*A_PtrSize, "ptr") - Item := NumGet(ptr, 4*A_PtrSize, "ptr") - pTimeProc := NumGet(ptr, 5*A_PtrSize, "ptr") + frame := NumGet(ptr + 1*A_PtrSize, "int") + current := NumGet(ptr + 2*A_PtrSize, "int") + pBitmap := NumGet(ptr + 3*A_PtrSize, "ptr") + Item := NumGet(ptr + 4*A_PtrSize, "ptr") + pTimeProc := NumGet(ptr + 5*A_PtrSize, "ptr") ; Get next frame. frames := NumGet(Item + 4, "uint") // 4 ; Total number of frames frame := mod(frame + 1, frames) ; Loop back to zero - ; Get delay. + ; Get delay. See: https://www.biphelps.com/blog/The-Fastest-GIF-Does-Not-Exist delays := NumGet(Item + 8 + A_PtrSize, "ptr") ; Array of delays delay := 10 * NumGet(delays + 4*frame, "uint") ; Delay of next frame delay := max(delay, 10) ; Minimum delay is 10ms (delay == 10) && delay := 100 ; 10 ms is actually 100 ms - ; See: https://www.biphelps.com/blog/The-Fastest-GIF-Does-Not-Exist ; Check delay. current += 10 ; Add resolution of timer - NumPut("int", current, ptr, 2*A_PtrSize) ; Save the current delay + NumPut("int", current, ptr + 2*A_PtrSize) ; Save the current delay ; Note that the rounding errors may accumulate, but it will even out over time. - ; This checks every 10 ms. Using <= 5 ensures that the range will always be 10 ms. - if ! (abs(current - delay) <= 5) + ; This checks every 10 ms. Using <= 5 ensures that the range will always be 10 ms. + ; Will execute by frame number rather than timing, due to the current delay being incremented by 10. + if ! (abs(current - delay) <= 5) return - NumPut("int", frame, ptr, 1*A_PtrSize) ; Save the frame number - NumPut("int", 0, ptr, 2*A_PtrSize) ; Reset the current delay + NumPut("int", frame, ptr + 1*A_PtrSize) ; Save the frame number + NumPut("int", 0, ptr + 2*A_PtrSize) ; Reset the current delay /* ; Debug code - static start := 0, sum := 0, count := 1 + static start := 0, sum := 0, count := 0 DllCall("QueryPerformanceFrequency", "int64*", &frequency:=0) DllCall("QueryPerformanceCounter", "int64*", &now:=0) time := (now - start) / frequency * 1000 if (time < 10000) { sum += time count += 1 - if (mod(count, 10) = 0) ; Prevent the tooltip from impacting timings - Tooltip "Current Delay:`t" Round(time, 4) - . "`nAverage Delay:`t" Round(sum / count, 4) - . "`nPlanned Delay:`t" (delay ?? "unknown") + ;if (mod(count, 10) = 0) ; Prevent the tooltip from impacting timings + Tooltip "Current Delay:`t" Round(time, 4) + . "`n" "Average Delay:`t" Round(sum / count, 4) + . "`n" "Planned Delay:`t" (delay ?? "unknown") } start := now */ From ed9ea7074917ba73db30a447ca72d00204f542d0 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 12 Sep 2023 20:13:12 -0400 Subject: [PATCH 438/492] C source files From b44b6e37360fa987598329ce3b47fd3619f0c7a8 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 12 Sep 2023 20:50:03 -0400 Subject: [PATCH 439/492] comment --- ImagePut (for v1).ahk | 4 +++- ImagePut.ahk | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 5130139a..c278cf04 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -3232,7 +3232,9 @@ class ImagePut { ; Note that the rounding errors may accumulate, but it will even out over time. ; This checks every 10 ms. Using <= 5 ensures that the range will always be 10 ms. - ; Will execute by frame number rather than timing, due to the current delay being incremented by 10. + ; Will execute by frame number rather than timing, which is more accurate, + ; because the timing will rely take into account the above overhead, + ; whereas the frame number will always form an even distribution. if ! (abs(current - delay) <= 5) return diff --git a/ImagePut.ahk b/ImagePut.ahk index bf3252f4..025faf6d 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -3232,7 +3232,9 @@ class ImagePut { ; Note that the rounding errors may accumulate, but it will even out over time. ; This checks every 10 ms. Using <= 5 ensures that the range will always be 10 ms. - ; Will execute by frame number rather than timing, due to the current delay being incremented by 10. + ; Will execute by frame number rather than timing, which is more accurate, + ; because the timing will rely take into account the above overhead, + ; whereas the frame number will always form an even distribution. if ! (abs(current - delay) <= 5) return From cd61c1258ebb4ac65d35b1f5ccdeee4fd09bc86b Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 12 Sep 2023 21:18:13 -0400 Subject: [PATCH 440/492] Clarify condition for GIF delay --- ImagePut (for v1).ahk | 6 +++--- ImagePut.ahk | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index c278cf04..8d50c0e5 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -3230,12 +3230,12 @@ class ImagePut { current += 10 ; Add resolution of timer NumPut(current, ptr + 2*A_PtrSize, "int") ; Save the current delay - ; Note that the rounding errors may accumulate, but it will even out over time. - ; This checks every 10 ms. Using <= 5 ensures that the range will always be 10 ms. + ; Check if the current tick is equal to the delay. ; Will execute by frame number rather than timing, which is more accurate, ; because the timing will rely take into account the above overhead, ; whereas the frame number will always form an even distribution. - if ! (abs(current - delay) <= 5) + ; Note that the variance (jitter) is additive, yet reverts to zero over time. + if (current != delay) return NumPut( frame, ptr + 1*A_PtrSize, "int") ; Save the frame number diff --git a/ImagePut.ahk b/ImagePut.ahk index 025faf6d..086dc5da 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -3230,12 +3230,12 @@ class ImagePut { current += 10 ; Add resolution of timer NumPut("int", current, ptr + 2*A_PtrSize) ; Save the current delay - ; Note that the rounding errors may accumulate, but it will even out over time. - ; This checks every 10 ms. Using <= 5 ensures that the range will always be 10 ms. + ; Check if the current tick is equal to the delay. ; Will execute by frame number rather than timing, which is more accurate, ; because the timing will rely take into account the above overhead, ; whereas the frame number will always form an even distribution. - if ! (abs(current - delay) <= 5) + ; Note that the variance (jitter) is additive, yet reverts to zero over time. + if (current != delay) return NumPut("int", frame, ptr + 1*A_PtrSize) ; Save the frame number From b555dc0ef16d67973cc6ba8dac16bec569d43c8c Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 15 Sep 2023 10:31:49 -0400 Subject: [PATCH 441/492] Set old protect from VirtualProtect to 0 --- ImagePut (for v1).ahk | 10 +++++----- ImagePut.ahk | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 8d50c0e5..d3571a12 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1840,7 +1840,7 @@ class ImagePut { s64 := StrLen(RTrim(b64, "=")) * 3 // 4 code := DllCall("GlobalAlloc", "uint", 0, "uptr", s64, "ptr") DllCall("crypt32\CryptStringToBinary", "str", b64, "uint", 0, "uint", 0x1, "ptr", code, "uint*", s64, "ptr", 0, "ptr", 0) - DllCall("VirtualProtect", "ptr", code, "ptr", s64, "uint", 0x40, "uint*", op:=0) + DllCall("VirtualProtect", "ptr", code, "ptr", s64, "uint", 0x40, "uint*", 0) } ; Sample the top-left pixel and set all matching pixels to be transparent. @@ -2284,7 +2284,7 @@ class ImagePut { s64 := StrLen(RTrim(b64, "=")) * 3 // 4 code := DllCall("GlobalAlloc", "uint", 0, "uptr", s64, "ptr") DllCall("crypt32\CryptStringToBinary", "str", b64, "uint", 0, "uint", 0x1, "ptr", code, "uint*", s64, "ptr", 0, "ptr", 0) - DllCall("VirtualProtect", "ptr", code, "ptr", s64, "uint", 0x40, "uint*", op:=0) + DllCall("VirtualProtect", "ptr", code, "ptr", s64, "uint", 0x40, "uint*", 0) return codes[b64] := code } @@ -2300,7 +2300,7 @@ class ImagePut { s64 := StrLen(RTrim(b64, "=")) * 3 // 4 code := DllCall("GlobalAlloc", "uint", 0, "uptr", s64, "ptr") DllCall("crypt32\CryptStringToBinary", "str", b64, "uint", 0, "uint", 0x1, "ptr", code, "uint*", s64, "ptr", 0, "ptr", 0) - DllCall("VirtualProtect", "ptr", code, "ptr", s64, "uint", 0x40, "uint*", op:=0) + DllCall("VirtualProtect", "ptr", code, "ptr", s64, "uint", 0x40, "uint*", 0) ; Set eax flag to 1 to retrieve supported CPU features. ; See this for CPU features: https://wiki.osdev.org/CPUID @@ -3539,7 +3539,7 @@ class ImagePut { s64 := StrLen(RTrim(b64, "=")) * 3 // 4 code := DllCall("GlobalAlloc", "uint", 0, "uptr", s64, "ptr") DllCall("crypt32\CryptStringToBinary", "str", b64, "uint", 0, "uint", 0x1, "ptr", code, "uint*", s64, "ptr", 0, "ptr", 0) - DllCall("VirtualProtect", "ptr", code, "ptr", s64, "uint", 0x40, "uint*", op:=0) + DllCall("VirtualProtect", "ptr", code, "ptr", s64, "uint", 0x40, "uint*", 0) } ; Default to lowercase hex values. Or capitalize the string below. @@ -3575,7 +3575,7 @@ class ImagePut { s64 := StrLen(RTrim(b64, "=")) * 3 // 4 code := DllCall("GlobalAlloc", "uint", 0, "uptr", s64, "ptr") DllCall("crypt32\CryptStringToBinary", "str", b64, "uint", 0, "uint", 0x1, "ptr", code, "uint*", s64, "ptr", 0, "ptr", 0) - DllCall("VirtualProtect", "ptr", code, "ptr", s64, "uint", 0x40, "uint*", op:=0) + DllCall("VirtualProtect", "ptr", code, "ptr", s64, "uint", 0x40, "uint*", 0) } ; Default to lowercase hex values. Or capitalize the string below. diff --git a/ImagePut.ahk b/ImagePut.ahk index 086dc5da..5c0dc1a5 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1840,7 +1840,7 @@ class ImagePut { s64 := StrLen(RTrim(b64, "=")) * 3 // 4 code := DllCall("GlobalAlloc", "uint", 0, "uptr", s64, "ptr") DllCall("crypt32\CryptStringToBinary", "str", b64, "uint", 0, "uint", 0x1, "ptr", code, "uint*", s64, "ptr", 0, "ptr", 0) - DllCall("VirtualProtect", "ptr", code, "ptr", s64, "uint", 0x40, "uint*", &op:=0) + DllCall("VirtualProtect", "ptr", code, "ptr", s64, "uint", 0x40, "uint*", 0) } ; Sample the top-left pixel and set all matching pixels to be transparent. @@ -2284,7 +2284,7 @@ class ImagePut { s64 := StrLen(RTrim(b64, "=")) * 3 // 4 code := DllCall("GlobalAlloc", "uint", 0, "uptr", s64, "ptr") DllCall("crypt32\CryptStringToBinary", "str", b64, "uint", 0, "uint", 0x1, "ptr", code, "uint*", s64, "ptr", 0, "ptr", 0) - DllCall("VirtualProtect", "ptr", code, "ptr", s64, "uint", 0x40, "uint*", &op:=0) + DllCall("VirtualProtect", "ptr", code, "ptr", s64, "uint", 0x40, "uint*", 0) return codes[b64] := code } @@ -2300,7 +2300,7 @@ class ImagePut { s64 := StrLen(RTrim(b64, "=")) * 3 // 4 code := DllCall("GlobalAlloc", "uint", 0, "uptr", s64, "ptr") DllCall("crypt32\CryptStringToBinary", "str", b64, "uint", 0, "uint", 0x1, "ptr", code, "uint*", s64, "ptr", 0, "ptr", 0) - DllCall("VirtualProtect", "ptr", code, "ptr", s64, "uint", 0x40, "uint*", &op:=0) + DllCall("VirtualProtect", "ptr", code, "ptr", s64, "uint", 0x40, "uint*", 0) ; Set eax flag to 1 to retrieve supported CPU features. ; See this for CPU features: https://wiki.osdev.org/CPUID @@ -3539,7 +3539,7 @@ class ImagePut { s64 := StrLen(RTrim(b64, "=")) * 3 // 4 code := DllCall("GlobalAlloc", "uint", 0, "uptr", s64, "ptr") DllCall("crypt32\CryptStringToBinary", "str", b64, "uint", 0, "uint", 0x1, "ptr", code, "uint*", s64, "ptr", 0, "ptr", 0) - DllCall("VirtualProtect", "ptr", code, "ptr", s64, "uint", 0x40, "uint*", &op:=0) + DllCall("VirtualProtect", "ptr", code, "ptr", s64, "uint", 0x40, "uint*", 0) } ; Default to lowercase hex values. Or capitalize the string below. @@ -3575,7 +3575,7 @@ class ImagePut { s64 := StrLen(RTrim(b64, "=")) * 3 // 4 code := DllCall("GlobalAlloc", "uint", 0, "uptr", s64, "ptr") DllCall("crypt32\CryptStringToBinary", "str", b64, "uint", 0, "uint", 0x1, "ptr", code, "uint*", s64, "ptr", 0, "ptr", 0) - DllCall("VirtualProtect", "ptr", code, "ptr", s64, "uint", 0x40, "uint*", &op:=0) + DllCall("VirtualProtect", "ptr", code, "ptr", s64, "uint", 0x40, "uint*", 0) } ; Default to lowercase hex values. Or capitalize the string below. From 408c8742874baeca0e9eee463fbe4cb1796f7149 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 15 Sep 2023 11:04:19 -0400 Subject: [PATCH 442/492] cpuid comment for posterity --- ImagePut (for v1).ahk | 3 ++- ImagePut.ahk | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index d3571a12..30d1eace 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2304,7 +2304,8 @@ class ImagePut { ; Set eax flag to 1 to retrieve supported CPU features. ; See this for CPU features: https://wiki.osdev.org/CPUID - ; Also see page 591: https://www.amd.com/system/files/TechDocs/24594.pdf + ; Also see: Appendix D.2 - CPUID Feature Flags Related to Instruction Support + ; On page 1861 - https://www.amd.com/content/dam/amd/en/documents/processor-tech-docs/programmer-references/40332.pdf DllCall(code, "uint*", a := 1, "uint*", b := 0, "uint*", c := 0, "uint*", d := 0, "cdecl") ; Free memory. diff --git a/ImagePut.ahk b/ImagePut.ahk index 5c0dc1a5..b1c56acf 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2304,7 +2304,8 @@ class ImagePut { ; Set eax flag to 1 to retrieve supported CPU features. ; See this for CPU features: https://wiki.osdev.org/CPUID - ; Also see page 591: https://www.amd.com/system/files/TechDocs/24594.pdf + ; Also see: Appendix D.2 - CPUID Feature Flags Related to Instruction Support + ; On page 1861 - https://www.amd.com/content/dam/amd/en/documents/processor-tech-docs/programmer-references/40332.pdf DllCall(code, "uint*", &a := 1, "uint*", &b := 0, "uint*", &c := 0, "uint*", &d := 0, "cdecl") ; Free memory. From df1a280b3e4be6845b84b608e75fab42a5f21570 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 15 Sep 2023 11:55:35 -0400 Subject: [PATCH 443/492] Add check for AVX (not AVX2!) --- ImagePut (for v1).ahk | 11 +++++++++++ ImagePut.ahk | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 30d1eace..e23fe9d2 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2289,6 +2289,17 @@ class ImagePut { return codes[b64] := code } + AVX2() { + ; This is just plain old AVX, not a check for AVX2 (which is neexed for pixelsearch1y) + ; Also see: https://store.steampowered.com/hwsurvey/steam-hardware-software-survey-welcome-to-steam + ; C source code - https://godbolt.org/z/n8fxxdsfs + code := this.Base64Code((A_PtrSize == 4) + ? "VYnli0UIi1UQi00UO0UMcws5EHUCiQiDwATr8F3D" ; not implemented + : "U0UxwLgBAAAARInBD6IPuuEbcxkPuuEccxNEicEPAdBI99CoBg+UwA+2wOsCMcBbww==") + + return DllCall(code, "int") + } + CPUID() { static cpuid := 0 diff --git a/ImagePut.ahk b/ImagePut.ahk index b1c56acf..162bd6b6 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2289,6 +2289,17 @@ class ImagePut { return codes[b64] := code } + AVX2() { + ; This is just plain old AVX, not a check for AVX2 (which is neexed for pixelsearch1y) + ; Also see: https://store.steampowered.com/hwsurvey/steam-hardware-software-survey-welcome-to-steam + ; C source code - https://godbolt.org/z/n8fxxdsfs + code := this.Base64Code((A_PtrSize == 4) + ? "VYnli0UIi1UQi00UO0UMcws5EHUCiQiDwATr8F3D" ; not implemented + : "U0UxwLgBAAAARInBD6IPuuEbcxkPuuEccxNEicEPAdBI99CoBg+UwA+2wOsCMcBbww==") + + return DllCall(code, "int") + } + CPUID() { static cpuid := 0 From ead79107ed0c5256e97dc00a710bf6cdf20617c6 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 16 Sep 2023 01:29:49 -0400 Subject: [PATCH 444/492] Simplify Tooltip Destruction --- ImagePut (for v1).ahk | 15 +++++---------- ImagePut.ahk | 7 +------ 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index e23fe9d2..f742b25b 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -3196,18 +3196,13 @@ class ImagePut { DllCall("SendMessage", "ptr", tt, "uint", 1044, "ptr", text_color, "ptr", 0) ; Destroy tooltip after 7 seconds of the last showing. - static tick - tick := A_TickCount - pWndProc := RegisterCallback(ImagePut.WindowProc,,, &ImagePut) - clock := Func("DllCall").bind(pWndProc, "ptr", hwnd, "uint", 0x8001, "uptr", A_TickCount, "ptr", pWndProc) - SetTimer % clock, -7000 - } + SetTimer Tooltip, -7000 + goto default - if (uMsg = 0x8001) - if (tick == wParam) { ; tock is wParam + Tooltip: Tooltip - DllCall("GlobalFree", "ptr", lParam, "ptr") ; pWndProc is lParam - } + return + } ; WM_APP - Animate GIFs if (uMsg = 0x8000) { diff --git a/ImagePut.ahk b/ImagePut.ahk index 162bd6b6..d6dd878a 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -3196,9 +3196,7 @@ class ImagePut { DllCall("SendMessage", "ptr", tt, "uint", 1044, "ptr", text_color, "ptr", 0) ; Destroy tooltip after 7 seconds of the last showing. - static tick ; Using a static allows changes in value to affect tick inside the closure. - tick := A_TickCount ; Change and update tick. tock is set only once using bind to eval A_TickCount. - SetTimer (tock => (tick == tock) && Tooltip()).Bind(A_TickCount), -7000 + SetTimer Tooltip, -7000 } @@ -3206,9 +3204,6 @@ class ImagePut { - - - ; WM_APP - Animate GIFs if (uMsg = 0x8000) { ; Thanks tmplinshi, Teadrinker - https://www.autohotkey.com/boards/viewtopic.php?f=76&t=83358 From 8b676a3c11700bf06735a2c0bc4f8c710e4937dd Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 16 Sep 2023 02:09:40 -0400 Subject: [PATCH 445/492] Use Tooltip No. 16 --- ImagePut (for v1).ahk | 4 ++-- ImagePut.ahk | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index f742b25b..ad2ab4c2 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -3187,7 +3187,7 @@ class ImagePut { text_color := (0.3*(255&c>>16) + 0.59*(255&c>>8) + 0.11*(255&c)) >= 128 ? 0x000000 : 0xFFFFFF ; Show tooltip. - Tooltip % " (" x ", " y ") `n " SubStr(c, 3) " " + Tooltip % " (" x ", " y ") `n " SubStr(c, 3) " ",,, 16 tt := WinExist("ahk_class tooltips_class32 ahk_exe" A_AhkPath) ; Style background and text color. @@ -3200,7 +3200,7 @@ class ImagePut { goto default Tooltip: - Tooltip + Tooltip,,,, 16 return } diff --git a/ImagePut.ahk b/ImagePut.ahk index d6dd878a..47af04a7 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -3187,7 +3187,7 @@ class ImagePut { text_color := (0.3*(255&c>>16) + 0.59*(255&c>>8) + 0.11*(255&c)) >= 128 ? 0x000000 : 0xFFFFFF ; Show tooltip. - tt := Tooltip(" (" x ", " y ") `n " SubStr(c, 3) " ") + tt := Tooltip(" (" x ", " y ") `n " SubStr(c, 3) " ",,, 16) ; Style background and text color. @@ -3196,7 +3196,7 @@ class ImagePut { DllCall("SendMessage", "ptr", tt, "uint", 1044, "ptr", text_color, "ptr", 0) ; Destroy tooltip after 7 seconds of the last showing. - SetTimer Tooltip, -7000 + SetTimer Tooltip.bind(,,, 16), -7000 } From 2415cc8f6fd47abb15292a3fb290e3d5b5eb79d1 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 16 Sep 2023 20:00:08 -0400 Subject: [PATCH 446/492] C source files change encodings From ba9da4d54edce2815711b6dbc873baf2e489118e Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 16 Sep 2023 20:02:07 -0400 Subject: [PATCH 447/492] C source files Add pixelsearch3x.c --- source/pixelsearch3x.c | 76 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 source/pixelsearch3x.c diff --git a/source/pixelsearch3x.c b/source/pixelsearch3x.c new file mode 100644 index 00000000..05eaec04 --- /dev/null +++ b/source/pixelsearch3x.c @@ -0,0 +1,76 @@ +#include + +unsigned int * pixelsearch3(unsigned int * start, unsigned int * end, unsigned int * colors, unsigned int length) { + + unsigned int * current = start; + __m128i vstart, vcolor0, vcolor1, vcolor2; + + int i = 0; + + enter: + start = current; // Reset pointer for each run. + if (length - i > 2) + goto check_3; + else if (length - i > 1) + goto check_2; + else if (length - i > 0) + goto check_1; + else + goto exit; + + check_3: + vcolor0 = _mm_set1_epi32(*(colors + i + 0)); + vcolor1 = _mm_set1_epi32(*(colors + i + 1)); + vcolor2 = _mm_set1_epi32(*(colors + i + 2)); + + while (start < end - 3) { + vstart = _mm_loadu_si128((__m128i *) start); + if (_mm_movemask_epi8(_mm_cmpeq_epi32(vcolor0, vstart)) != 0) + goto exit; + if (_mm_movemask_epi8(_mm_cmpeq_epi32(vcolor1, vstart)) != 0) + goto exit; + if (_mm_movemask_epi8(_mm_cmpeq_epi32(vcolor2, vstart)) != 0) + goto exit; + start += 4; + } + i += 3; + goto enter; + + check_2: + vcolor0 = _mm_set1_epi32(*(colors + i + 0)); + vcolor1 = _mm_set1_epi32(*(colors + i + 1)); + + while (start < end - 3) { + vstart = _mm_loadu_si128((__m128i *) start); + if (_mm_movemask_epi8(_mm_cmpeq_epi32(vcolor0, vstart)) != 0) + goto exit; + if (_mm_movemask_epi8(_mm_cmpeq_epi32(vcolor1, vstart)) != 0) + goto exit; + start += 4; + } + i += 2; + goto enter; + + check_1: + vcolor0 = _mm_set1_epi32(*(colors + i + 0)); + + while (start < end - 3) { + vstart = _mm_loadu_si128((__m128i *) start); + if (_mm_movemask_epi8(_mm_cmpeq_epi32(vcolor0, vstart)) != 0) + goto exit; + start += 4; + } + i += 1; + goto enter; + + exit: + // Clean up any remaining elements. + while (start < end) { + for (int i = 0; i < length; i++) + if (*start == colors[i]) + return start; + start++; + } + + return start; // start == end if no match. +} \ No newline at end of file From 6829268a2716ec488dea11ec0f3855208faec0bf Mon Sep 17 00:00:00 2001 From: anonymous1184 <53758552+anonymous1184@users.noreply.github.com> Date: Sun, 17 Sep 2023 01:10:17 -0600 Subject: [PATCH 448/492] Avoid recursion limit error in AHK_H Reference: thqby/AutoHotkey_H#73 --- ImagePut.ahk | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index dba914c0..aafa7e66 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -242,8 +242,8 @@ class ImagePut { return coimage } - static get(name, p*) { - return ObjHasOwnProp(this, name) ? this.name : "" + static get(self, name) { + return ObjHasOwnProp(self, name) ? self.%name% : "" } static inputs := [ @@ -279,7 +279,7 @@ class ImagePut { static DontVerifyImageType(&image, &keywords := "") { ; Sentinel value: Returns the empty string for unknown properties. - keywords := {base: {__get: this.get}} + keywords := {base: {__get: (self, name, *) => this.get(self, name)}} ; Try ImageType. if !IsObject(image) @@ -288,7 +288,7 @@ class ImagePut { ; Goto ImageType. if ObjHasOwnProp(image, "image") { keywords := image - keywords.base := {__get: this.get} + keywords.base := {__get: (self, name, *) => this.get(self, name)} image := image.image throw Error("Must catch this error with ImageType.") } @@ -297,7 +297,7 @@ class ImagePut { for type in this.inputs if ObjHasOwnProp(image, type) { keywords := image - keywords.base := {__get: this.get} + keywords.base := {__get: (self, name, *) => this.get(self, name)} image := image.%type% return type } @@ -437,7 +437,7 @@ class ImagePut { static ToBitmap(type, image, k := "") { ; Sentinel value: Returns the empty string for unknown properties. - (!k) && k := {base: {__get: this.get}} + (!k) && k := {__get: (self, name, *) => this.get(self, name)} if (type = "clipboard_png") return this.from_clipboard_png() @@ -614,7 +614,7 @@ class ImagePut { static ToStream(type, image, k := "") { ; Sentinel value: Returns the empty string for unknown properties. - (!k) && k := {base: {__get: this.get}} + (!k) && k := {__get: (self, name, *) => this.get(self, name)} if (type = "clipboard_png") return this.get_clipboard_png() From aceeaed855e91a423c0972b03dff06907a5a435f Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 22 Sep 2023 13:09:39 -0400 Subject: [PATCH 449/492] Simplify PixelSearch3 --- ImagePut (for v1).ahk | 20 +++++++++----------- ImagePut.ahk | 20 +++++++++----------- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index ad2ab4c2..ab0803e9 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2430,18 +2430,16 @@ class ImagePut { . "1GYP3tlmD3TQZg903A9U02YPdtVmRA/XwkWFwHUSSIPAEOvLikgCQTjLcwtIg8AESDnQcu/rHTjZcvGKSAFAOM5y6UA4+XLkighA" . "OM1y3UQ44XLYW15fXUFcQV1BXsM=") - ; C source code - https://godbolt.org/z/veshd46qn + ; C source code - https://godbolt.org/z/1vj98cocW pixelsearch3 := this.Base64Code((A_PtrSize == 4) - ? "VTHSieVXVlOD5PCD7BCLXQyLTRCNQ/SJRCQMi0UUKdCD+AJ2KGYPbiyRZg9udJEEjXP0Zg9ufJEIi0UIZg9w3QBmD3DOAGYPcNcA" - . "63V1IGYPbiyRZg9udJEEjXP0i0UIZg9w1QBmD3DOAOmAAAAAO1UUdBJmD248kYtFCGYPcM8A6YcAAACLRQjpnQAAAA8QAA8o4GYP" - . "duNmD9f8hf8PhYcAAAAPKOBmD3bhZg/X/IX/dXhmD3bCZg/X+IX/dWyDwBA58HLIg8ID6U3///8PEAAPKNpmD3bYZg/X+4X/dUtm" - . "D3bBZg/X+IX/dT+DwBA58HLbg8IC6SD///8PEABmD3bBZg/X8IX2dSGDwBCLdCQMOfBy5kLpAP///4s0kTkwdBFCO1UUdfODwAQ5" - . "2HMEMdLr8I1l9FteX13D" - : "VlNJicpIidEx0kyNWfREicgp0IP4AnYySGPCSI1Z9GZBD24sgGZBD25UgAhmD3DdAGZBD25sgARmD3DSAEyJ0GYPcM0A6YQAAAB1" - . "JkhjwkiNWfRmQQ9uLIBmQQ9uTIAETInQZg9w1QBmD3DJAOmLAAAARDnKdBZIY8JmQQ9uFIBMidBmD3DKAOmQAAAATInQ6akAAAAP" - . "EAAPKOBmD3bjZg/X9IX2D4WTAAAADyjgZg924WYP1/SF9g+FgAAAAGYPdsJmD9fwhfZ1dEiDwBBIOdhywoPCA+kz////DxAADyja" - . "Zg922GYP1/OF9nVRZg92wWYP1/CF9nVFSIPAEEg52HLZg8IC6QT///8PEABmD3bBZg/X2IXbdSVIg8AQTDnYcuj/wunl/v//SP/C" - . "QYtckPw5GHQSRDnKcu9Ig8AESDnIcwQx0uvuW17D") + ? "VTHSieVXi00MVlOLXRCLRRQp0A+E5QAAAIP4AXQbg/gCdAtmD25skwhmD3DdAGYPbnSTBGYPcNYAZg9uPJNmD3DPAIP4AXR6g/gC" + . "jXH0i0UIdGM58HM2DxAADyjgZg924WYP1/yF/w+FiQAAAA8o4mYPduBmD9f8hf91emYPdsNmD9f4hf91boPAEOvGg8ID6Xn///8P" + . "EAAPKOFmD3bgZg/X/IX/dU9mD3bCZg/X+IX/dUODwBA58HLbg8IC6Uz///+LRQiNcfQ58HMUDxAAZg92wWYP1/iF/3Ubg8AQ6+hC" + . "6Sj///+LNJM5MHQTQjtVFHXzg8AEOchzBjHS6/CJyFteX13D" + : "U0mJykiJ0THSTI1Z9ESJyCnQD4T2AAAASGPag/gBdB2D+AJ0DGZBD25smAhmD3DdAGZBD25smARmD3DVAGZBD24MmGYPcMkAg/gB" + . "dH+D+AJMidB0akw52HM7DxAADyjgZg924WYP19yF2w+FlQAAAA8o4mYPduBmD9fchdsPhYIAAABmD3bDZg/X2IXbdXZIg8AQ68CD" + . "wgPpcP///w8QAA8o4WYPduBmD9fchdt1VmYPdsJmD9fYhdt1SkiDwBBMOdhy2YPCAulB////TInQTDnYcxUPEABmD3bBZg/X2IXb" + . "dSJIg8AQ6+b/wukd////SP/CQYtckPw5GHQVRDnKcu9Ig8AESDnIcwcx0uvuSInIW8M=") ; C source code - https://godbolt.org/z/oEGGeedac pixelsearch4 := this.Base64Code((A_PtrSize == 4) diff --git a/ImagePut.ahk b/ImagePut.ahk index c5046710..0986bffc 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2430,18 +2430,16 @@ class ImagePut { . "1GYP3tlmD3TQZg903A9U02YPdtVmRA/XwkWFwHUSSIPAEOvLikgCQTjLcwtIg8AESDnQcu/rHTjZcvGKSAFAOM5y6UA4+XLkighA" . "OM1y3UQ44XLYW15fXUFcQV1BXsM=") - ; C source code - https://godbolt.org/z/veshd46qn + ; C source code - https://godbolt.org/z/1vj98cocW pixelsearch3 := this.Base64Code((A_PtrSize == 4) - ? "VTHSieVXVlOD5PCD7BCLXQyLTRCNQ/SJRCQMi0UUKdCD+AJ2KGYPbiyRZg9udJEEjXP0Zg9ufJEIi0UIZg9w3QBmD3DOAGYPcNcA" - . "63V1IGYPbiyRZg9udJEEjXP0i0UIZg9w1QBmD3DOAOmAAAAAO1UUdBJmD248kYtFCGYPcM8A6YcAAACLRQjpnQAAAA8QAA8o4GYP" - . "duNmD9f8hf8PhYcAAAAPKOBmD3bhZg/X/IX/dXhmD3bCZg/X+IX/dWyDwBA58HLIg8ID6U3///8PEAAPKNpmD3bYZg/X+4X/dUtm" - . "D3bBZg/X+IX/dT+DwBA58HLbg8IC6SD///8PEABmD3bBZg/X8IX2dSGDwBCLdCQMOfBy5kLpAP///4s0kTkwdBFCO1UUdfODwAQ5" - . "2HMEMdLr8I1l9FteX13D" - : "VlNJicpIidEx0kyNWfREicgp0IP4AnYySGPCSI1Z9GZBD24sgGZBD25UgAhmD3DdAGZBD25sgARmD3DSAEyJ0GYPcM0A6YQAAAB1" - . "JkhjwkiNWfRmQQ9uLIBmQQ9uTIAETInQZg9w1QBmD3DJAOmLAAAARDnKdBZIY8JmQQ9uFIBMidBmD3DKAOmQAAAATInQ6akAAAAP" - . "EAAPKOBmD3bjZg/X9IX2D4WTAAAADyjgZg924WYP1/SF9g+FgAAAAGYPdsJmD9fwhfZ1dEiDwBBIOdhywoPCA+kz////DxAADyja" - . "Zg922GYP1/OF9nVRZg92wWYP1/CF9nVFSIPAEEg52HLZg8IC6QT///8PEABmD3bBZg/X2IXbdSVIg8AQTDnYcuj/wunl/v//SP/C" - . "QYtckPw5GHQSRDnKcu9Ig8AESDnIcwQx0uvuW17D") + ? "VTHSieVXi00MVlOLXRCLRRQp0A+E5QAAAIP4AXQbg/gCdAtmD25skwhmD3DdAGYPbnSTBGYPcNYAZg9uPJNmD3DPAIP4AXR6g/gC" + . "jXH0i0UIdGM58HM2DxAADyjgZg924WYP1/yF/w+FiQAAAA8o4mYPduBmD9f8hf91emYPdsNmD9f4hf91boPAEOvGg8ID6Xn///8P" + . "EAAPKOFmD3bgZg/X/IX/dU9mD3bCZg/X+IX/dUODwBA58HLbg8IC6Uz///+LRQiNcfQ58HMUDxAAZg92wWYP1/iF/3Ubg8AQ6+hC" + . "6Sj///+LNJM5MHQTQjtVFHXzg8AEOchzBjHS6/CJyFteX13D" + : "U0mJykiJ0THSTI1Z9ESJyCnQD4T2AAAASGPag/gBdB2D+AJ0DGZBD25smAhmD3DdAGZBD25smARmD3DVAGZBD24MmGYPcMkAg/gB" + . "dH+D+AJMidB0akw52HM7DxAADyjgZg924WYP19yF2w+FlQAAAA8o4mYPduBmD9fchdsPhYIAAABmD3bDZg/X2IXbdXZIg8AQ68CD" + . "wgPpcP///w8QAA8o4WYPduBmD9fchdt1VmYPdsJmD9fYhdt1SkiDwBBMOdhy2YPCAulB////TInQTDnYcxUPEABmD3bBZg/X2IXb" + . "dSJIg8AQ6+b/wukd////SP/CQYtckPw5GHQVRDnKcu9Ig8AESDnIcwcx0uvuSInIW8M=") ; C source code - https://godbolt.org/z/oEGGeedac pixelsearch4 := this.Base64Code((A_PtrSize == 4) From 17a92f75d54f1a1c0a0feb4d7f7b9d8f1d5e12f5 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 22 Sep 2023 13:39:34 -0400 Subject: [PATCH 450/492] Speedup pixelsearch4 --- ImagePut (for v1).ahk | 27 +++++++++++++++++++++++---- ImagePut.ahk | 27 +++++++++++++++++++++++---- 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index ab0803e9..ce6f4b4b 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2430,7 +2430,7 @@ class ImagePut { . "1GYP3tlmD3TQZg903A9U02YPdtVmRA/XwkWFwHUSSIPAEOvLikgCQTjLcwtIg8AESDnQcu/rHTjZcvGKSAFAOM5y6UA4+XLkighA" . "OM1y3UQ44XLYW15fXUFcQV1BXsM=") - ; C source code - https://godbolt.org/z/1vj98cocW + ; C source code - https://godbolt.org/z/xj5seEhba pixelsearch3 := this.Base64Code((A_PtrSize == 4) ? "VTHSieVXi00MVlOLXRCLRRQp0A+E5QAAAIP4AXQbg/gCdAtmD25skwhmD3DdAGYPbnSTBGYPcNYAZg9uPJNmD3DPAIP4AXR6g/gC" . "jXH0i0UIdGM58HM2DxAADyjgZg924WYP1/yF/w+FiQAAAA8o4mYPduBmD9f8hf91emYPdsNmD9f4hf91boPAEOvGg8ID6Xn///8P" @@ -2441,10 +2441,25 @@ class ImagePut { . "wgPpcP///w8QAA8o4WYPduBmD9fchdt1VmYPdsJmD9fYhdt1SkiDwBBMOdhy2YPCAulB////TInQTDnYcxUPEABmD3bBZg/X2IXb" . "dSJIg8AQ6+b/wukd////SP/CQYtckPw5GHQVRDnKcu9Ig8AESDnIcwcx0uvuSInIW8M=") - ; C source code - https://godbolt.org/z/oEGGeedac + ; C source code - https://godbolt.org/z/W54vWW7Gz pixelsearch4 := this.Base64Code((A_PtrSize == 4) - ? "VYnlV1ZTUYt1EIt9FItVCDtVDHNFikICiloBiEXzigKIRfIxwDtFGHQrik3zOEyGAnIfOkyHAnIZOFyGAXITOlyHAXINik3yOAyGcgU6DIdzCEDr0IPCBOu2idBaW15fXcM=" - : "U0iJyEg50HNFRIpQAkSKWAExyYoYO0wkMHMtRThUiAJyIUU6VIkCchpFOFyIAXITRTpciQFyDEE4HIhyBkE6HIlzC0j/wevNSIPABOu2W8M=") + ? "VTHSieVXVlOD5PCD7CCLdRCLTRSLRRgp0A+EDAIAAIP4AXQ6g/gCdB9mD25klghmD3DsAA8pbCQQZg9ubJEIZg9w3QAPKRwkZg9u" + . "ZJYEZg9uVJEEZg9w3ABmD3DqAGYPbiSWZg9uNJFmD3DUAGYPcOYAg/gBD4QdAQAAg/gCi0UID4SlAAAAi30MZg929o1f9DnYD4OL" + . "AAAADxAADyj6DyjIZg/e+GYP3sxmD3T6Zg90yA9Uz2YPds5mD9f5hf8PhSgBAAAPKMsPKPhmD97IZg/e/WYPdMtmD3T4D1TPZg92" + . "zmYP1/mF/w+F/wAAAA8oPCQPKEwkEGYP3vhmD97IZg90TCQQZg90xw9UyGYPds5mD9f5hf8PhdEAAACDwBDpbf///4PCA+no/v//" + . "i10MZg929oPrDDnYc1YPEAAPKPgPKMhmD978Zg/eymYPdMpmD3T4D1TPZg92zmYP1/mF/w+FhwAAAA8o+A8oy2YP3shmD979Zg90" + . "y2YPdMcPVMhmD3bOZg/X+YX/dWKDwBDrpoPCAul8/v//i30Mi0UIZg929o1f9DnYcy0PEAgPEAAPEDhmD97MZg/ewmYPdMJmD3TP" + . "D1TBZg92xmYP1/iF/3Ucg8AQ689C6Tj+//+J+zhclgJzIkI7VRh18oPABDtFDHM8ilABD7Z4AohUJBCKEIgUJDHS6986XJECctiK" + . "XCQQOFyWAXLOOlyRAXLIihwkOByWcsA6HJFyu+sDi0UMjWX0W15fXcM=" + : "VlNIg+xIDyk0JA8pfCQQRA8pRCQgRA8pTCQwi5wkgAAAAEmJykiJ0THSSI1x9EGJ20Ep0w+EEwIAAEhjwkGD+wF0NkGD+wJ0GGZB" + . "D250gAhmQQ9ubIEIZg9w5gBmD3D1AGZBD25cgARmQQ9ubIEEZg9w0wBmD3DtAGZBD24cgGZFD3bAZg9wywBmQQ9uHIFMidBmD3Db" + . "AEGD+wEPhFcBAABBg/sCD4QOAQAASDnwD4ObAAAADxAARA8oyQ8o+GZED97IZg/e+2ZED3TJZg90+EEPVPlmQQ92+GZED9ffRYXb" + . "D4UvAQAADyj6RA8oyGYP3vhmRA/ezWYPdPpmRA90yEEPVPlmQQ92+GZED9ffRYXbD4X/AAAARA8oyA8o/GYP3vhmRA/ezmYPdPxm" + . "QQ90wQ9Ux2ZBD3bAZkQP19hFhdsPhdAAAABIg8AQ6Vz///+DwgPp1/7//w8QAEQPKMgPKPhmRA/ey2YP3vlmD3T5ZkQPdMhBD1T5" + . "ZkEPdvhmRA/X30WF2w+FjAAAAEQPKMgPKPpmD974ZkQP3s1mD3T6ZkEPdMEPVMdmQQ92wGZED9fYRYXbdWFIg8AQSDnwcpmDwgLp" + . "aP7//w8QOEQPKM8PKMdmRA/ey2YP3sFmD3TBZkEPdPkPVMdmQQ92wGZED9fYRYXbdSJIg8AQSDnwcsn/wukq/v//RThUkAJzH0j/" + . "wjnacvJIg8AESDnIczVEilACRIpYATHSQIow6+RFOlSRAnLaRThckAFy00U6XJEBcsxBODSQcsZBOjSRcsDrA0iJyA8oNCQPKHwk" + . "EEQPKEQkIEQPKEwkMEiDxEhbXsM=") ; ------------------------------------------------------------------------------------------------------ @@ -2523,10 +2538,12 @@ class ImagePut { b := ((c & 0xFF)) v := abs(variation) + NumPut(255, high, 4*A_Offset + 3, "uchar") ; Alpha NumPut(min(r+v, 255), high, 4*A_Offset + 2, "uchar") NumPut(min(g+v, 255), high, 4*A_Offset + 1, "uchar") NumPut(min(b+v, 255), high, 4*A_Offset + 0, "uchar") + NumPut(0, low, 4*A_Offset + 3, "uchar") ; Alpha NumPut(max(r-v, 0), low, 4*A_Offset + 2, "uchar") NumPut(max(g-v, 0), low, 4*A_Offset + 1, "uchar") NumPut(max(b-v, 0), low, 4*A_Offset + 0, "uchar") @@ -2549,10 +2566,12 @@ class ImagePut { vg := abs(variation[2]) vb := abs(variation[3]) + NumPut(255, high, 4*A_Offset + 3, "uchar") ; Alpha NumPut(min(r + vr, 255), high, 4*A_Offset + 2, "uchar") NumPut(min(g + vg, 255), high, 4*A_Offset + 1, "uchar") NumPut(min(b + vb, 255), high, 4*A_Offset + 0, "uchar") + NumPut(0, low, 4*A_Offset + 3, "uchar") ; Alpha NumPut(max(r - vr, 0), low, 4*A_Offset + 2, "uchar") NumPut(max(g - vg, 0), low, 4*A_Offset + 1, "uchar") NumPut(max(b - vb, 0), low, 4*A_Offset + 0, "uchar") diff --git a/ImagePut.ahk b/ImagePut.ahk index 0986bffc..1eef24e8 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2430,7 +2430,7 @@ class ImagePut { . "1GYP3tlmD3TQZg903A9U02YPdtVmRA/XwkWFwHUSSIPAEOvLikgCQTjLcwtIg8AESDnQcu/rHTjZcvGKSAFAOM5y6UA4+XLkighA" . "OM1y3UQ44XLYW15fXUFcQV1BXsM=") - ; C source code - https://godbolt.org/z/1vj98cocW + ; C source code - https://godbolt.org/z/xj5seEhba pixelsearch3 := this.Base64Code((A_PtrSize == 4) ? "VTHSieVXi00MVlOLXRCLRRQp0A+E5QAAAIP4AXQbg/gCdAtmD25skwhmD3DdAGYPbnSTBGYPcNYAZg9uPJNmD3DPAIP4AXR6g/gC" . "jXH0i0UIdGM58HM2DxAADyjgZg924WYP1/yF/w+FiQAAAA8o4mYPduBmD9f8hf91emYPdsNmD9f4hf91boPAEOvGg8ID6Xn///8P" @@ -2441,10 +2441,25 @@ class ImagePut { . "wgPpcP///w8QAA8o4WYPduBmD9fchdt1VmYPdsJmD9fYhdt1SkiDwBBMOdhy2YPCAulB////TInQTDnYcxUPEABmD3bBZg/X2IXb" . "dSJIg8AQ6+b/wukd////SP/CQYtckPw5GHQVRDnKcu9Ig8AESDnIcwcx0uvuSInIW8M=") - ; C source code - https://godbolt.org/z/oEGGeedac + ; C source code - https://godbolt.org/z/W54vWW7Gz pixelsearch4 := this.Base64Code((A_PtrSize == 4) - ? "VYnlV1ZTUYt1EIt9FItVCDtVDHNFikICiloBiEXzigKIRfIxwDtFGHQrik3zOEyGAnIfOkyHAnIZOFyGAXITOlyHAXINik3yOAyGcgU6DIdzCEDr0IPCBOu2idBaW15fXcM=" - : "U0iJyEg50HNFRIpQAkSKWAExyYoYO0wkMHMtRThUiAJyIUU6VIkCchpFOFyIAXITRTpciQFyDEE4HIhyBkE6HIlzC0j/wevNSIPABOu2W8M=") + ? "VTHSieVXVlOD5PCD7CCLdRCLTRSLRRgp0A+EDAIAAIP4AXQ6g/gCdB9mD25klghmD3DsAA8pbCQQZg9ubJEIZg9w3QAPKRwkZg9u" + . "ZJYEZg9uVJEEZg9w3ABmD3DqAGYPbiSWZg9uNJFmD3DUAGYPcOYAg/gBD4QdAQAAg/gCi0UID4SlAAAAi30MZg929o1f9DnYD4OL" + . "AAAADxAADyj6DyjIZg/e+GYP3sxmD3T6Zg90yA9Uz2YPds5mD9f5hf8PhSgBAAAPKMsPKPhmD97IZg/e/WYPdMtmD3T4D1TPZg92" + . "zmYP1/mF/w+F/wAAAA8oPCQPKEwkEGYP3vhmD97IZg90TCQQZg90xw9UyGYPds5mD9f5hf8PhdEAAACDwBDpbf///4PCA+no/v//" + . "i10MZg929oPrDDnYc1YPEAAPKPgPKMhmD978Zg/eymYPdMpmD3T4D1TPZg92zmYP1/mF/w+FhwAAAA8o+A8oy2YP3shmD979Zg90" + . "y2YPdMcPVMhmD3bOZg/X+YX/dWKDwBDrpoPCAul8/v//i30Mi0UIZg929o1f9DnYcy0PEAgPEAAPEDhmD97MZg/ewmYPdMJmD3TP" + . "D1TBZg92xmYP1/iF/3Ucg8AQ689C6Tj+//+J+zhclgJzIkI7VRh18oPABDtFDHM8ilABD7Z4AohUJBCKEIgUJDHS6986XJECctiK" + . "XCQQOFyWAXLOOlyRAXLIihwkOByWcsA6HJFyu+sDi0UMjWX0W15fXcM=" + : "VlNIg+xIDyk0JA8pfCQQRA8pRCQgRA8pTCQwi5wkgAAAAEmJykiJ0THSSI1x9EGJ20Ep0w+EEwIAAEhjwkGD+wF0NkGD+wJ0GGZB" + . "D250gAhmQQ9ubIEIZg9w5gBmD3D1AGZBD25cgARmQQ9ubIEEZg9w0wBmD3DtAGZBD24cgGZFD3bAZg9wywBmQQ9uHIFMidBmD3Db" + . "AEGD+wEPhFcBAABBg/sCD4QOAQAASDnwD4ObAAAADxAARA8oyQ8o+GZED97IZg/e+2ZED3TJZg90+EEPVPlmQQ92+GZED9ffRYXb" + . "D4UvAQAADyj6RA8oyGYP3vhmRA/ezWYPdPpmRA90yEEPVPlmQQ92+GZED9ffRYXbD4X/AAAARA8oyA8o/GYP3vhmRA/ezmYPdPxm" + . "QQ90wQ9Ux2ZBD3bAZkQP19hFhdsPhdAAAABIg8AQ6Vz///+DwgPp1/7//w8QAEQPKMgPKPhmRA/ey2YP3vlmD3T5ZkQPdMhBD1T5" + . "ZkEPdvhmRA/X30WF2w+FjAAAAEQPKMgPKPpmD974ZkQP3s1mD3T6ZkEPdMEPVMdmQQ92wGZED9fYRYXbdWFIg8AQSDnwcpmDwgLp" + . "aP7//w8QOEQPKM8PKMdmRA/ey2YP3sFmD3TBZkEPdPkPVMdmQQ92wGZED9fYRYXbdSJIg8AQSDnwcsn/wukq/v//RThUkAJzH0j/" + . "wjnacvJIg8AESDnIczVEilACRIpYATHSQIow6+RFOlSRAnLaRThckAFy00U6XJEBcsxBODSQcsZBOjSRcsDrA0iJyA8oNCQPKHwk" + . "EEQPKEQkIEQPKEwkMEiDxEhbXsM=") ; ------------------------------------------------------------------------------------------------------ @@ -2523,10 +2538,12 @@ class ImagePut { b := ((c & 0xFF)) v := abs(variation) + NumPut("uchar", 255, high, 4*A_Offset + 3) ; Alpha NumPut("uchar", min(r+v, 255), high, 4*A_Offset + 2) NumPut("uchar", min(g+v, 255), high, 4*A_Offset + 1) NumPut("uchar", min(b+v, 255), high, 4*A_Offset + 0) + NumPut("uchar", 0, low, 4*A_Offset + 3) ; Alpha NumPut("uchar", max(r-v, 0), low, 4*A_Offset + 2) NumPut("uchar", max(g-v, 0), low, 4*A_Offset + 1) NumPut("uchar", max(b-v, 0), low, 4*A_Offset + 0) @@ -2549,10 +2566,12 @@ class ImagePut { vg := abs(variation[2]) vb := abs(variation[3]) + NumPut("uchar", 255, high, 4*A_Offset + 3) ; Alpha NumPut("uchar", min(r + vr, 255), high, 4*A_Offset + 2) NumPut("uchar", min(g + vg, 255), high, 4*A_Offset + 1) NumPut("uchar", min(b + vb, 255), high, 4*A_Offset + 0) + NumPut("uchar", 0, low, 4*A_Offset + 3) ; Alpha NumPut("uchar", max(r - vr, 0), low, 4*A_Offset + 2) NumPut("uchar", max(g - vg, 0), low, 4*A_Offset + 1) NumPut("uchar", max(b - vb, 0), low, 4*A_Offset + 0) From 27a027f20f65d91837c5afa51c2b8e82e74d3c9f Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 22 Sep 2023 13:43:27 -0400 Subject: [PATCH 451/492] C source files Cleanup pixelsearch3x Add pixelsearch4x --- source/pixelsearch3x.c | 69 ++++++++++++-------- source/pixelsearch4x.c | 141 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 183 insertions(+), 27 deletions(-) create mode 100644 source/pixelsearch4x.c diff --git a/source/pixelsearch3x.c b/source/pixelsearch3x.c index 05eaec04..cc5aefda 100644 --- a/source/pixelsearch3x.c +++ b/source/pixelsearch3x.c @@ -2,61 +2,76 @@ unsigned int * pixelsearch3(unsigned int * start, unsigned int * end, unsigned int * colors, unsigned int length) { + // Save the starting pointer position. unsigned int * current = start; - __m128i vstart, vcolor0, vcolor1, vcolor2; - + + // Offset of pointer to stored colors. int i = 0; + // Number of colors left. + int n; + + // Determine how many matches to be run in sequence. enter: - start = current; // Reset pointer for each run. - if (length - i > 2) - goto check_3; - else if (length - i > 1) - goto check_2; - else if (length - i > 0) + n = length - i; + if (n == 0) + return end; // Somehow goto exit creates a bigger binary in mcodeforgcc (not here though). + if (n == 1) + goto init_1; + if (n == 2) + goto init_2; + if (n > 2) + goto init_3; // Segue into next label. + + // Create vectors from pointer to stored colors. + init_3: + __m128i vcolor3 = _mm_set1_epi32(*(colors + i + 2)); + init_2: + __m128i vcolor2 = _mm_set1_epi32(*(colors + i + 1)); + init_1: + __m128i vcolor1 = _mm_set1_epi32(*(colors + i + 0)); + + // Restore starting pointer for each run. + start = current; + + // Somehow there are diminishing returns past running 3 checks at once. + if (n == 1) goto check_1; - else - goto exit; + if (n == 2) + goto check_2; + if (n > 2) + goto check_3; // Segue into next label. check_3: - vcolor0 = _mm_set1_epi32(*(colors + i + 0)); - vcolor1 = _mm_set1_epi32(*(colors + i + 1)); - vcolor2 = _mm_set1_epi32(*(colors + i + 2)); - while (start < end - 3) { - vstart = _mm_loadu_si128((__m128i *) start); - if (_mm_movemask_epi8(_mm_cmpeq_epi32(vcolor0, vstart)) != 0) - goto exit; + __m128i vstart = _mm_loadu_si128((__m128i *) start); if (_mm_movemask_epi8(_mm_cmpeq_epi32(vcolor1, vstart)) != 0) goto exit; if (_mm_movemask_epi8(_mm_cmpeq_epi32(vcolor2, vstart)) != 0) goto exit; + if (_mm_movemask_epi8(_mm_cmpeq_epi32(vcolor3, vstart)) != 0) + goto exit; start += 4; } i += 3; goto enter; check_2: - vcolor0 = _mm_set1_epi32(*(colors + i + 0)); - vcolor1 = _mm_set1_epi32(*(colors + i + 1)); - while (start < end - 3) { - vstart = _mm_loadu_si128((__m128i *) start); - if (_mm_movemask_epi8(_mm_cmpeq_epi32(vcolor0, vstart)) != 0) - goto exit; + __m128i vstart = _mm_loadu_si128((__m128i *) start); if (_mm_movemask_epi8(_mm_cmpeq_epi32(vcolor1, vstart)) != 0) goto exit; + if (_mm_movemask_epi8(_mm_cmpeq_epi32(vcolor2, vstart)) != 0) + goto exit; start += 4; } i += 2; goto enter; check_1: - vcolor0 = _mm_set1_epi32(*(colors + i + 0)); - while (start < end - 3) { - vstart = _mm_loadu_si128((__m128i *) start); - if (_mm_movemask_epi8(_mm_cmpeq_epi32(vcolor0, vstart)) != 0) + __m128i vstart = _mm_loadu_si128((__m128i *) start); + if (_mm_movemask_epi8(_mm_cmpeq_epi32(vcolor1, vstart)) != 0) goto exit; start += 4; } diff --git a/source/pixelsearch4x.c b/source/pixelsearch4x.c new file mode 100644 index 00000000..03339500 --- /dev/null +++ b/source/pixelsearch4x.c @@ -0,0 +1,141 @@ +#include + +#define _mm_cmpge_epu8(a, b) _mm_cmpeq_epi8(_mm_max_epu8(a, b), a) +#define _mm_cmple_epu8(a, b) _mm_cmpge_epu8(b, a) +#define _mm_cmpgt_epu8(a, b) _mm_xor_si128(_mm_cmple_epu8(a, b), _mm_set1_epi8(-1)) +#define _mm_cmplt_epu8(a, b) _mm_cmpgt_epu8(b, a) + +unsigned int * pixelsearch4(unsigned int * start, unsigned int * end, unsigned int * high, unsigned int * low, unsigned int length) { + + // Save the starting pointer position. + unsigned int * current = start; + + // Offset of pointer to stored colors. + int i = 0; + + // Number of colors left. + int n; + + // Comparison mask for unsigned integers. + __m128i vmask = _mm_set1_epi32(0xFFFFFFFF); + + // Determine how many matches to be run in sequence. + enter: + n = length - i; + if (n == 0) + return end; // Somehow goto exit creates a bigger binary in mcodeforgcc (not here though). + if (n == 1) + goto init_1; + if (n == 2) + goto init_2; + if (n > 2) + goto init_3; // Segue into next label. + + // Create vectors. + init_3: + __m128i vh3 = _mm_set1_epi32(*(high + i + 2)); + __m128i vl3 = _mm_set1_epi32(*(low + i + 2)); + init_2: + __m128i vh2 = _mm_set1_epi32(*(high + i + 1)); + __m128i vl2 = _mm_set1_epi32(*(low + i + 1)); + init_1: + __m128i vh1 = _mm_set1_epi32(*(high + i + 0)); + __m128i vl1 = _mm_set1_epi32(*(low + i + 0)); + + // Restore starting pointer for each run. + start = current; + + // Somehow there are diminishing returns past running 3 checks at once. + if (n == 1) + goto check_1; + if (n == 2) + goto check_2; + if (n > 2) + goto check_3; // Segue into next label. + + check_3: + while (start < end - 3) { + __m128i vstart = _mm_loadu_si128((__m128i *) start); + + if (_mm_movemask_epi8(_mm_cmpeq_epi32(vmask, + _mm_and_si128( + _mm_cmple_epu8(vstart, vh1), + _mm_cmpge_epu8(vstart, vl1)))) != 0) + goto exit; + if (_mm_movemask_epi8(_mm_cmpeq_epi32(vmask, + _mm_and_si128( + _mm_cmple_epu8(vstart, vh2), + _mm_cmpge_epu8(vstart, vl2)))) != 0) + goto exit; + if (_mm_movemask_epi8(_mm_cmpeq_epi32(vmask, + _mm_and_si128( + _mm_cmple_epu8(vstart, vh3), + _mm_cmpge_epu8(vstart, vl3)))) != 0) + goto exit; + + start += 4; + } + i += 3; + goto enter; + + check_2: + while (start < end - 3) { + __m128i vstart = _mm_loadu_si128((__m128i *) start); + + if (_mm_movemask_epi8(_mm_cmpeq_epi32(vmask, + _mm_and_si128( + _mm_cmple_epu8(vstart, vh1), + _mm_cmpge_epu8(vstart, vl1)))) != 0) + goto exit; + if (_mm_movemask_epi8(_mm_cmpeq_epi32(vmask, + _mm_and_si128( + _mm_cmple_epu8(vstart, vh2), + _mm_cmpge_epu8(vstart, vl2)))) != 0) + goto exit; + + start += 4; + } + i += 2; + goto enter; + + check_1: + while (start < end - 3) { + __m128i vstart = _mm_loadu_si128((__m128i *) start); + + if (_mm_movemask_epi8(_mm_cmpeq_epi32(vmask, + _mm_and_si128( + _mm_cmple_epu8(vstart, vh1), + _mm_cmpge_epu8(vstart, vl1)))) != 0) + goto exit; + + start += 4; + } + i += 1; + goto enter; + + exit: + // Clean up any remaining elements. + unsigned char r, g, b, rh, gh, bh, rl, gl, bl; + while (start < end) { + + r = *((unsigned char *) start + 2); + g = *((unsigned char *) start + 1); + b = *((unsigned char *) start + 0); + + for (int i = 0; i < length; i++) { + + rh = *((unsigned char *) high + 4*i + 2); + gh = *((unsigned char *) high + 4*i + 1); + bh = *((unsigned char *) high + 4*i + 0); + rl = *((unsigned char *) low + 4*i + 2); + gl = *((unsigned char *) low + 4*i + 1); + bl = *((unsigned char *) low + 4*i + 0); + + if (rh >= r && r >= rl && gh >= g && g >= gl && bh >= b && b >= bl) + return start; + } + start++; + } + + return start; // start == end if no match. +} \ No newline at end of file From 74c41aadce61da71f31448bf787c7925ac43793a Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 22 Sep 2023 20:32:11 -0400 Subject: [PATCH 452/492] Refactor PixelSearchAll --- ImagePut (for v1).ahk | 238 ++++++++++++++++++++++++++++++++++++----- ImagePut.ahk | 242 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 428 insertions(+), 52 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index ce6f4b4b..ecb87c8e 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2376,15 +2376,15 @@ class ImagePut { DllCall(code, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "uchar", alpha, "cdecl") } - PixelSearch(color, variation := 0) { + ; Option 1: PixelSearch, single color with no variation. + ; Option 2: PixelSearch, single color with single variation. + ; Option 3: PixelSearch, single color with multiple variation. + ; Option 4: PixelSearch, range of colors. + ; Option 5: PixelSearch, multiple colors with no variation. + ; Option 6: PixelSearch, multiple colors with single variation. + ; Option 7: PixelSearch, multiple colors with multiple variation. - ; Option 1: PixelSearch, single color with no variation. - ; Option 2: PixelSearch, single color with single variation. - ; Option 3: PixelSearch, single color with multiple variation. - ; Option 4: PixelSearch, range of colors. - ; Option 5: PixelSearch, multiple colors with no variation. - ; Option 6: PixelSearch, multiple colors with single variation. - ; Option 7: PixelSearch, multiple colors with multiple variation. + PixelSearch(color, variation := 0) { if not IsObject(color) { @@ -2463,8 +2463,8 @@ class ImagePut { ; ------------------------------------------------------------------------------------------------------ + ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. if (option == 1) - ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. byte := DllCall(pixelsearch1, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "cdecl ptr") if (option == 2) { @@ -2589,24 +2589,213 @@ class ImagePut { return [mod(offset, this.width), offset // this.width] } - PixelSearchAll(color) { - ; C source code - https://godbolt.org/z/zPY1qMvYe - PixelSearch3 := this.Base64Code((A_PtrSize == 4) - ? "VTHAieVTi1UQi00UOcpzGItdGDkadQw7RQxzBotdCIkUg0CDwgTr5Ftdww==" + PixelSearchAll(color, variation := 0) { + + if not IsObject(color) { + + ; Lift color to 32-bits if first 8 bits are zero. + (color >> 24) || color |= 0xFF000000 + + if not IsObject(variation) + if (variation == 0) + option := 1 + else + option := 2 + else if (variation.length() == 3) + option := 3 + else if (variation.length() == 6) + option := 4 + else throw Exception("Invalid variation parameter.") + } + else + if not IsObject(variation) + if (variation == 0) + option := 5 + else + option := 6 + else if (variation.length() == 3) + option := 7 + else throw Exception("Invalid variation parameter.") + + ; ----------------------- Machine code generated with MCode4GCC using gcc 13.2.0 ----------------------- + + ; C source code - https://godbolt.org/z/6jPnc6b5s + pixelsearchall1 := this.Base64Code((A_PtrSize == 4) + ? "VYnlVotNEItVDFOLRQhmD27RjVr0Zg9wygA52HMbDxAAZg92wWYP1/CF9nUMg8AQ6+g5CHQHg8AEOdBy9VteXcM=" : "McBEi1QkKE05yHMYRTkQdQ050HMHQYnDTokE2f/ASYPABOvjww==") - ; Lift color to 32-bits if first 8 bits are zero. - (color >> 24) || color |= 0xFF000000 + ; C source code - https://godbolt.org/z/7fv3P6KTb + pixelsearchall2 := this.Base64Code((A_PtrSize == 4) + ? "VWYPduSJ5VdWU4Pk8IPsEIpFFItdEItNGItVHIt1DIt9IIhEJA6KRSSIXCQPD7bbiEwkDcHjEA+2yYhEJAsPtkUgweEIiFQkDA+2" + . "0gnYweIICcgPtk0kDQAAAP8J0Q+2VRRmD27oi0UIZg9wzQDB4hAJ0Y1W9GYPbvFmD3DWADnQczkPEAAPEBgPEDhmD97BZg/e2mYP" + . "dMFmD3TfD1TDZg92xGYP18iFyXURg8AQ68+KUAI4VCQPcwmDwAQ58HLw6yM6VCQOcvGKUAE4VCQNcug6VCQMcuKKEIn5ONFy2jpU" + . "JAty1I1l9FteX13D" + : "QVZBVUFUVVdWU0SLbCRgi0QkaESLdCRwRItUJHhEie6Jx0UPtu0PtsBBweUIRIn1RQ+29kWJ1EWJw0UPtsBEicvB4AhBweAQRQ+2" + . "0kUPtslFCfBECdBBweEQRQnoRAnIQYHIAAAA/2YPbuhIichmQQ9uyEiNSvRmD3DBAGYPcM0AZg927Ug5yHM8DxAgDyjQDyjcZg/e" + . "1GYP3tlmD3TQZg903A9U02YPdtVmRA/XwkWFwHUSSIPAEOvLikgCQTjLcwtIg8AESDnQcu/rHTjZcvGKSAFAOM5y6UA4+XLkighA" + . "OM1y3UQ44XLYW15fXUFcQV1BXsM=") - ; PixelSearchAll, single color, no variation - capacity := 256 - VarSetCapacity(result, A_PtrSize * capacity) - count := DllCall(PixelSearch3, "ptr", &result, "uint", capacity, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "cdecl uint") + ; C source code - https://godbolt.org/z/xj5seEhba + pixelsearchall3 := this.Base64Code((A_PtrSize == 4) + ? "VTHSieVXi00MVlOLXRCLRRQp0A+E5QAAAIP4AXQbg/gCdAtmD25skwhmD3DdAGYPbnSTBGYPcNYAZg9uPJNmD3DPAIP4AXR6g/gC" + . "jXH0i0UIdGM58HM2DxAADyjgZg924WYP1/yF/w+FiQAAAA8o4mYPduBmD9f8hf91emYPdsNmD9f4hf91boPAEOvGg8ID6Xn///8P" + . "EAAPKOFmD3bgZg/X/IX/dU9mD3bCZg/X+IX/dUODwBA58HLbg8IC6Uz///+LRQiNcfQ58HMUDxAAZg92wWYP1/iF/3Ubg8AQ6+hC" + . "6Sj///+LNJM5MHQTQjtVFHXzg8AEOchzBjHS6/CJyFteX13D" + : "U0mJykiJ0THSTI1Z9ESJyCnQD4T2AAAASGPag/gBdB2D+AJ0DGZBD25smAhmD3DdAGZBD25smARmD3DVAGZBD24MmGYPcMkAg/gB" + . "dH+D+AJMidB0akw52HM7DxAADyjgZg924WYP19yF2w+FlQAAAA8o4mYPduBmD9fchdsPhYIAAABmD3bDZg/X2IXbdXZIg8AQ68CD" + . "wgPpcP///w8QAA8o4WYPduBmD9fchdt1VmYPdsJmD9fYhdt1SkiDwBBMOdhy2YPCAulB////TInQTDnYcxUPEABmD3bBZg/X2IXb" + . "dSJIg8AQ6+b/wukd////SP/CQYtckPw5GHQVRDnKcu9Ig8AESDnIcwcx0uvuSInIW8M=") - ; If the default 256 results is exceeded, run the function again. - if (count > capacity) { - VarSetCapacity(result, A_PtrSize * count) - count := DllCall(PixelSearch3, "ptr", &result, "uint", count, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "cdecl uint") + ; C source code - https://godbolt.org/z/W54vWW7Gz + pixelsearchall4 := this.Base64Code((A_PtrSize == 4) + ? "VTHSieVXVlOD5PCD7CCLdRCLTRSLRRgp0A+EDAIAAIP4AXQ6g/gCdB9mD25klghmD3DsAA8pbCQQZg9ubJEIZg9w3QAPKRwkZg9u" + . "ZJYEZg9uVJEEZg9w3ABmD3DqAGYPbiSWZg9uNJFmD3DUAGYPcOYAg/gBD4QdAQAAg/gCi0UID4SlAAAAi30MZg929o1f9DnYD4OL" + . "AAAADxAADyj6DyjIZg/e+GYP3sxmD3T6Zg90yA9Uz2YPds5mD9f5hf8PhSgBAAAPKMsPKPhmD97IZg/e/WYPdMtmD3T4D1TPZg92" + . "zmYP1/mF/w+F/wAAAA8oPCQPKEwkEGYP3vhmD97IZg90TCQQZg90xw9UyGYPds5mD9f5hf8PhdEAAACDwBDpbf///4PCA+no/v//" + . "i10MZg929oPrDDnYc1YPEAAPKPgPKMhmD978Zg/eymYPdMpmD3T4D1TPZg92zmYP1/mF/w+FhwAAAA8o+A8oy2YP3shmD979Zg90" + . "y2YPdMcPVMhmD3bOZg/X+YX/dWKDwBDrpoPCAul8/v//i30Mi0UIZg929o1f9DnYcy0PEAgPEAAPEDhmD97MZg/ewmYPdMJmD3TP" + . "D1TBZg92xmYP1/iF/3Ucg8AQ689C6Tj+//+J+zhclgJzIkI7VRh18oPABDtFDHM8ilABD7Z4AohUJBCKEIgUJDHS6986XJECctiK" + . "XCQQOFyWAXLOOlyRAXLIihwkOByWcsA6HJFyu+sDi0UMjWX0W15fXcM=" + : "VlNIg+xIDyk0JA8pfCQQRA8pRCQgRA8pTCQwi5wkgAAAAEmJykiJ0THSSI1x9EGJ20Ep0w+EEwIAAEhjwkGD+wF0NkGD+wJ0GGZB" + . "D250gAhmQQ9ubIEIZg9w5gBmD3D1AGZBD25cgARmQQ9ubIEEZg9w0wBmD3DtAGZBD24cgGZFD3bAZg9wywBmQQ9uHIFMidBmD3Db" + . "AEGD+wEPhFcBAABBg/sCD4QOAQAASDnwD4ObAAAADxAARA8oyQ8o+GZED97IZg/e+2ZED3TJZg90+EEPVPlmQQ92+GZED9ffRYXb" + . "D4UvAQAADyj6RA8oyGYP3vhmRA/ezWYPdPpmRA90yEEPVPlmQQ92+GZED9ffRYXbD4X/AAAARA8oyA8o/GYP3vhmRA/ezmYPdPxm" + . "QQ90wQ9Ux2ZBD3bAZkQP19hFhdsPhdAAAABIg8AQ6Vz///+DwgPp1/7//w8QAEQPKMgPKPhmRA/ey2YP3vlmD3T5ZkQPdMhBD1T5" + . "ZkEPdvhmRA/X30WF2w+FjAAAAEQPKMgPKPpmD974ZkQP3s1mD3T6ZkEPdMEPVMdmQQ92wGZED9fYRYXbdWFIg8AQSDnwcpmDwgLp" + . "aP7//w8QOEQPKM8PKMdmRA/ey2YP3sFmD3TBZkEPdPkPVMdmQQ92wGZED9fYRYXbdSJIg8AQSDnwcsn/wukq/v//RThUkAJzH0j/" + . "wjnacvJIg8AESDnIczVEilACRIpYATHSQIow6+RFOlSRAnLaRThckAFy00U6XJEBcsxBODSQcsZBOjSRcsDrA0iJyA8oNCQPKHwk" + . "EEQPKEQkIEQPKEwkMEiDxEhbXsM=") + + ; ------------------------------------------------------------------------------------------------------ + + ; Global number of addresses (matching searches) to allocate. + limit := 256 + + ; If the limit is exceeded, the following routine will be run again. + redo: + VarSetCapacity(result, A_PtrSize * limit) ; Allocate buffer for addresses. + + ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. + if (option == 1) + count := DllCall(pixelsearchall1, "ptr", &result, "uint", limit, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "cdecl uint") + + if (option == 2) { + r := ((color & 0xFF0000) >> 16) + g := ((color & 0xFF00) >> 8) + b := ((color & 0xFF)) + v := abs(variation) + + count := DllCall(pixelsearch2, "ptr", &result, "uint", limit, "ptr", this.ptr, "ptr", this.ptr + this.size + , "uchar", min(r+v, 255) + , "uchar", max(r-v, 0) + , "uchar", min(g+v, 255) + , "uchar", max(g-v, 0) + , "uchar", min(b+v, 255) + , "uchar", max(b-v, 0) + , "cdecl ptr") + } + + if (option == 3) { + r := ((color & 0xFF0000) >> 16) + g := ((color & 0xFF00) >> 8) + b := ((color & 0xFF)) + vr := abs(variation[1]) + vg := abs(variation[2]) + vb := abs(variation[3]) + + count := DllCall(pixelsearch2, "ptr", &result, "uint", limit, "ptr", this.ptr, "ptr", this.ptr + this.size + , "uchar", min(r + vr, 255) + , "uchar", max(r - vr, 0) + , "uchar", min(g + vg, 255) + , "uchar", max(g - vg, 0) + , "uchar", min(b + vb, 255) + , "uchar", max(b - vb, 0) + , "cdecl ptr") + } + + if (option == 4) + count := DllCall(pixelsearch2, "ptr", &result, "uint", limit, "ptr", this.ptr, "ptr", this.ptr + this.size + , "uchar", min(max(variation[1], variation[2]), 255) + , "uchar", max(min(variation[1], variation[2]), 0) + , "uchar", min(max(variation[3], variation[4]), 255) + , "uchar", max(min(variation[3], variation[4]), 0) + , "uchar", min(max(variation[5], variation[6]), 255) + , "uchar", max(min(variation[5], variation[6]), 0) + , "cdecl ptr") + + if (option == 5) { + ; Create a struct of unsigned integers. + VarSetCapacity(colors, 4*color.length()) + + ; Fill the struct by iterating through the input array. + for i, c in color { + (c >> 24) || c |= 0xFF000000 ; Lift colors to 32-bit ARGB. + NumPut(c, colors, 4*(A_Index-1), "uint") ; Place the unsigned int at each offset. + } + + count := DllCall(pixelsearch3, "ptr", &result, "uint", limit, "ptr", this.ptr, "ptr", this.ptr + this.size, "ptr", &colors, "uint", color.length(), "cdecl ptr") + } + + ; Options 6 & 7 - Creates a high and low struct where each pair is the min and max range. + + if (option == 6) { + VarSetCapacity(high, 4*color.length()) + VarSetCapacity(low, 4*color.length()) + + for i, c in color { + A_Offset := A_Index - 1 + + r := ((c & 0xFF0000) >> 16) + g := ((c & 0xFF00) >> 8) + b := ((c & 0xFF)) + v := abs(variation) + + NumPut(255, high, 4*A_Offset + 3, "uchar") ; Alpha + NumPut(min(r+v, 255), high, 4*A_Offset + 2, "uchar") + NumPut(min(g+v, 255), high, 4*A_Offset + 1, "uchar") + NumPut(min(b+v, 255), high, 4*A_Offset + 0, "uchar") + + NumPut(0, low, 4*A_Offset + 3, "uchar") ; Alpha + NumPut(max(r-v, 0), low, 4*A_Offset + 2, "uchar") + NumPut(max(g-v, 0), low, 4*A_Offset + 1, "uchar") + NumPut(max(b-v, 0), low, 4*A_Offset + 0, "uchar") + } + + count := DllCall(pixelsearch4, "ptr", &result, "uint", limit, "ptr", this.ptr, "ptr", this.ptr + this.size, "ptr", &high, "ptr", &low, "uint", color.length(), "cdecl ptr") + } + + if (option == 7) { + VarSetCapacity(high, 4*color.length()) + VarSetCapacity(low, 4*color.length()) + + for i, c in color { + A_Offset := A_Index - 1 + + r := ((c & 0xFF0000) >> 16) + g := ((c & 0xFF00) >> 8) + b := ((c & 0xFF)) + vr := abs(variation[1]) + vg := abs(variation[2]) + vb := abs(variation[3]) + + NumPut(255, high, 4*A_Offset + 3, "uchar") ; Alpha + NumPut(min(r + vr, 255), high, 4*A_Offset + 2, "uchar") + NumPut(min(g + vg, 255), high, 4*A_Offset + 1, "uchar") + NumPut(min(b + vb, 255), high, 4*A_Offset + 0, "uchar") + + NumPut(0, low, 4*A_Offset + 3, "uchar") ; Alpha + NumPut(max(r - vr, 0), low, 4*A_Offset + 2, "uchar") + NumPut(max(g - vg, 0), low, 4*A_Offset + 1, "uchar") + NumPut(max(b - vb, 0), low, 4*A_Offset + 0, "uchar") + } + + count := DllCall(pixelsearch4, "ptr", &result, "uint", limit, "ptr", this.ptr, "ptr", this.ptr + this.size, "ptr", &high, "ptr", &low, "uint", color.length(), "cdecl ptr") + } + + ; If the default 256 results is exceeded, run the machine code again. + if (count > limit) { + limit := count + goto redo } ; Check if any matches are found. @@ -2618,8 +2807,7 @@ class ImagePut { loop % count { byte := NumGet(result, A_PtrSize*(A_Index-1), "ptr") offset := (byte - this.ptr) // 4 - xy := [mod(offset, this.width), offset // this.width] - xys.push(xy) + xys.push([mod(offset, this.width), offset // this.width]) } return xys } diff --git a/ImagePut.ahk b/ImagePut.ahk index 1eef24e8..b1700765 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2376,15 +2376,15 @@ class ImagePut { DllCall(code, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "uchar", alpha, "cdecl") } - PixelSearch(color, variation := 0) { + ; Option 1: PixelSearch, single color with no variation. + ; Option 2: PixelSearch, single color with single variation. + ; Option 3: PixelSearch, single color with multiple variation. + ; Option 4: PixelSearch, range of colors. + ; Option 5: PixelSearch, multiple colors with no variation. + ; Option 6: PixelSearch, multiple colors with single variation. + ; Option 7: PixelSearch, multiple colors with multiple variation. - ; Option 1: PixelSearch, single color with no variation. - ; Option 2: PixelSearch, single color with single variation. - ; Option 3: PixelSearch, single color with multiple variation. - ; Option 4: PixelSearch, range of colors. - ; Option 5: PixelSearch, multiple colors with no variation. - ; Option 6: PixelSearch, multiple colors with single variation. - ; Option 7: PixelSearch, multiple colors with multiple variation. + PixelSearch(color, variation := 0) { if not IsObject(color) { @@ -2463,8 +2463,8 @@ class ImagePut { ; ------------------------------------------------------------------------------------------------------ + ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. if (option == 1) - ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. byte := DllCall(pixelsearch1, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "cdecl ptr") if (option == 2) { @@ -2589,37 +2589,225 @@ class ImagePut { return [mod(offset, this.width), offset // this.width] } - PixelSearchAll(color) { - ; C source code - https://godbolt.org/z/zPY1qMvYe - PixelSearch3 := this.Base64Code((A_PtrSize == 4) - ? "VTHAieVTi1UQi00UOcpzGItdGDkadQw7RQxzBotdCIkUg0CDwgTr5Ftdww==" + PixelSearchAll(color, variation := 0) { + + if not IsObject(color) { + + ; Lift color to 32-bits if first 8 bits are zero. + (color >> 24) || color |= 0xFF000000 + + if not IsObject(variation) + if (variation == 0) + option := 1 + else + option := 2 + else if (variation.length == 3) + option := 3 + else if (variation.length == 6) + option := 4 + else throw Error("Invalid variation parameter.") + } + else + if not IsObject(variation) + if (variation == 0) + option := 5 + else + option := 6 + else if (variation.length == 3) + option := 7 + else throw Error("Invalid variation parameter.") + + ; ----------------------- Machine code generated with MCode4GCC using gcc 13.2.0 ----------------------- + + ; C source code - https://godbolt.org/z/6jPnc6b5s + pixelsearchall1 := this.Base64Code((A_PtrSize == 4) + ? "VYnlVotNEItVDFOLRQhmD27RjVr0Zg9wygA52HMbDxAAZg92wWYP1/CF9nUMg8AQ6+g5CHQHg8AEOdBy9VteXcM=" : "McBEi1QkKE05yHMYRTkQdQ050HMHQYnDTokE2f/ASYPABOvjww==") - ; Lift color to 32-bits if first 8 bits are zero. - (color >> 24) || color |= 0xFF000000 + ; C source code - https://godbolt.org/z/7fv3P6KTb + pixelsearchall2 := this.Base64Code((A_PtrSize == 4) + ? "VWYPduSJ5VdWU4Pk8IPsEIpFFItdEItNGItVHIt1DIt9IIhEJA6KRSSIXCQPD7bbiEwkDcHjEA+2yYhEJAsPtkUgweEIiFQkDA+2" + . "0gnYweIICcgPtk0kDQAAAP8J0Q+2VRRmD27oi0UIZg9wzQDB4hAJ0Y1W9GYPbvFmD3DWADnQczkPEAAPEBgPEDhmD97BZg/e2mYP" + . "dMFmD3TfD1TDZg92xGYP18iFyXURg8AQ68+KUAI4VCQPcwmDwAQ58HLw6yM6VCQOcvGKUAE4VCQNcug6VCQMcuKKEIn5ONFy2jpU" + . "JAty1I1l9FteX13D" + : "QVZBVUFUVVdWU0SLbCRgi0QkaESLdCRwRItUJHhEie6Jx0UPtu0PtsBBweUIRIn1RQ+29kWJ1EWJw0UPtsBEicvB4AhBweAQRQ+2" + . "0kUPtslFCfBECdBBweEQRQnoRAnIQYHIAAAA/2YPbuhIichmQQ9uyEiNSvRmD3DBAGYPcM0AZg927Ug5yHM8DxAgDyjQDyjcZg/e" + . "1GYP3tlmD3TQZg903A9U02YPdtVmRA/XwkWFwHUSSIPAEOvLikgCQTjLcwtIg8AESDnQcu/rHTjZcvGKSAFAOM5y6UA4+XLkighA" + . "OM1y3UQ44XLYW15fXUFcQV1BXsM=") - ; PixelSearchAll, single color, no variation - capacity := 256 - result := Buffer(A_PtrSize * capacity) - count := DllCall(PixelSearch3, "ptr", result, "uint", capacity, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "cdecl uint") + ; C source code - https://godbolt.org/z/xj5seEhba + pixelsearchall3 := this.Base64Code((A_PtrSize == 4) + ? "VTHSieVXi00MVlOLXRCLRRQp0A+E5QAAAIP4AXQbg/gCdAtmD25skwhmD3DdAGYPbnSTBGYPcNYAZg9uPJNmD3DPAIP4AXR6g/gC" + . "jXH0i0UIdGM58HM2DxAADyjgZg924WYP1/yF/w+FiQAAAA8o4mYPduBmD9f8hf91emYPdsNmD9f4hf91boPAEOvGg8ID6Xn///8P" + . "EAAPKOFmD3bgZg/X/IX/dU9mD3bCZg/X+IX/dUODwBA58HLbg8IC6Uz///+LRQiNcfQ58HMUDxAAZg92wWYP1/iF/3Ubg8AQ6+hC" + . "6Sj///+LNJM5MHQTQjtVFHXzg8AEOchzBjHS6/CJyFteX13D" + : "U0mJykiJ0THSTI1Z9ESJyCnQD4T2AAAASGPag/gBdB2D+AJ0DGZBD25smAhmD3DdAGZBD25smARmD3DVAGZBD24MmGYPcMkAg/gB" + . "dH+D+AJMidB0akw52HM7DxAADyjgZg924WYP19yF2w+FlQAAAA8o4mYPduBmD9fchdsPhYIAAABmD3bDZg/X2IXbdXZIg8AQ68CD" + . "wgPpcP///w8QAA8o4WYPduBmD9fchdt1VmYPdsJmD9fYhdt1SkiDwBBMOdhy2YPCAulB////TInQTDnYcxUPEABmD3bBZg/X2IXb" + . "dSJIg8AQ6+b/wukd////SP/CQYtckPw5GHQVRDnKcu9Ig8AESDnIcwcx0uvuSInIW8M=") - ; If the default 256 results is exceeded, run the function again. - if (count > capacity) { - result.size := A_PtrSize * count - count := DllCall(PixelSearch3, "ptr", result, "uint", count, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "cdecl uint") + ; C source code - https://godbolt.org/z/W54vWW7Gz + pixelsearchall4 := this.Base64Code((A_PtrSize == 4) + ? "VTHSieVXVlOD5PCD7CCLdRCLTRSLRRgp0A+EDAIAAIP4AXQ6g/gCdB9mD25klghmD3DsAA8pbCQQZg9ubJEIZg9w3QAPKRwkZg9u" + . "ZJYEZg9uVJEEZg9w3ABmD3DqAGYPbiSWZg9uNJFmD3DUAGYPcOYAg/gBD4QdAQAAg/gCi0UID4SlAAAAi30MZg929o1f9DnYD4OL" + . "AAAADxAADyj6DyjIZg/e+GYP3sxmD3T6Zg90yA9Uz2YPds5mD9f5hf8PhSgBAAAPKMsPKPhmD97IZg/e/WYPdMtmD3T4D1TPZg92" + . "zmYP1/mF/w+F/wAAAA8oPCQPKEwkEGYP3vhmD97IZg90TCQQZg90xw9UyGYPds5mD9f5hf8PhdEAAACDwBDpbf///4PCA+no/v//" + . "i10MZg929oPrDDnYc1YPEAAPKPgPKMhmD978Zg/eymYPdMpmD3T4D1TPZg92zmYP1/mF/w+FhwAAAA8o+A8oy2YP3shmD979Zg90" + . "y2YPdMcPVMhmD3bOZg/X+YX/dWKDwBDrpoPCAul8/v//i30Mi0UIZg929o1f9DnYcy0PEAgPEAAPEDhmD97MZg/ewmYPdMJmD3TP" + . "D1TBZg92xmYP1/iF/3Ucg8AQ689C6Tj+//+J+zhclgJzIkI7VRh18oPABDtFDHM8ilABD7Z4AohUJBCKEIgUJDHS6986XJECctiK" + . "XCQQOFyWAXLOOlyRAXLIihwkOByWcsA6HJFyu+sDi0UMjWX0W15fXcM=" + : "VlNIg+xIDyk0JA8pfCQQRA8pRCQgRA8pTCQwi5wkgAAAAEmJykiJ0THSSI1x9EGJ20Ep0w+EEwIAAEhjwkGD+wF0NkGD+wJ0GGZB" + . "D250gAhmQQ9ubIEIZg9w5gBmD3D1AGZBD25cgARmQQ9ubIEEZg9w0wBmD3DtAGZBD24cgGZFD3bAZg9wywBmQQ9uHIFMidBmD3Db" + . "AEGD+wEPhFcBAABBg/sCD4QOAQAASDnwD4ObAAAADxAARA8oyQ8o+GZED97IZg/e+2ZED3TJZg90+EEPVPlmQQ92+GZED9ffRYXb" + . "D4UvAQAADyj6RA8oyGYP3vhmRA/ezWYPdPpmRA90yEEPVPlmQQ92+GZED9ffRYXbD4X/AAAARA8oyA8o/GYP3vhmRA/ezmYPdPxm" + . "QQ90wQ9Ux2ZBD3bAZkQP19hFhdsPhdAAAABIg8AQ6Vz///+DwgPp1/7//w8QAEQPKMgPKPhmRA/ey2YP3vlmD3T5ZkQPdMhBD1T5" + . "ZkEPdvhmRA/X30WF2w+FjAAAAEQPKMgPKPpmD974ZkQP3s1mD3T6ZkEPdMEPVMdmQQ92wGZED9fYRYXbdWFIg8AQSDnwcpmDwgLp" + . "aP7//w8QOEQPKM8PKMdmRA/ey2YP3sFmD3TBZkEPdPkPVMdmQQ92wGZED9fYRYXbdSJIg8AQSDnwcsn/wukq/v//RThUkAJzH0j/" + . "wjnacvJIg8AESDnIczVEilACRIpYATHSQIow6+RFOlSRAnLaRThckAFy00U6XJEBcsxBODSQcsZBOjSRcsDrA0iJyA8oNCQPKHwk" + . "EEQPKEQkIEQPKEwkMEiDxEhbXsM=") + + ; ------------------------------------------------------------------------------------------------------ + + ; Global number of addresses (matching searches) to allocate. + limit := 256 + + ; If the limit is exceeded, the following routine will be run again. + redo: + result := Buffer(A_PtrSize * limit) ; Allocate buffer for addresses. + + ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. + if (option == 1) + count := DllCall(pixelsearchall1, "ptr", result, "uint", limit, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "cdecl uint") + + if (option == 2) { + r := ((color & 0xFF0000) >> 16) + g := ((color & 0xFF00) >> 8) + b := ((color & 0xFF)) + v := abs(variation) + + count := DllCall(pixelsearchall2, "ptr", result, "uint", limit, "ptr", this.ptr, "ptr", this.ptr + this.size + , "uchar", min(r+v, 255) + , "uchar", max(r-v, 0) + , "uchar", min(g+v, 255) + , "uchar", max(g-v, 0) + , "uchar", min(b+v, 255) + , "uchar", max(b-v, 0) + , "cdecl ptr") + } + + if (option == 3) { + r := ((color & 0xFF0000) >> 16) + g := ((color & 0xFF00) >> 8) + b := ((color & 0xFF)) + vr := abs(variation[1]) + vg := abs(variation[2]) + vb := abs(variation[3]) + + count := DllCall(pixelsearchall2, "ptr", result, "uint", limit, "ptr", this.ptr, "ptr", this.ptr + this.size + , "uchar", min(r + vr, 255) + , "uchar", max(r - vr, 0) + , "uchar", min(g + vg, 255) + , "uchar", max(g - vg, 0) + , "uchar", min(b + vb, 255) + , "uchar", max(b - vb, 0) + , "cdecl ptr") + } + + if (option == 4) + count := DllCall(pixelsearchall2, "ptr", result, "uint", limit, "ptr", this.ptr, "ptr", this.ptr + this.size + , "uchar", min(max(variation[1], variation[2]), 255) + , "uchar", max(min(variation[1], variation[2]), 0) + , "uchar", min(max(variation[3], variation[4]), 255) + , "uchar", max(min(variation[3], variation[4]), 0) + , "uchar", min(max(variation[5], variation[6]), 255) + , "uchar", max(min(variation[5], variation[6]), 0) + , "cdecl ptr") + + if (option == 5) { + ; Create a struct of unsigned integers. + colors := Buffer(4*color.length) + + ; Fill the struct by iterating through the input array. + for c in color { + (c >> 24) || c |= 0xFF000000 ; Lift colors to 32-bit ARGB. + NumPut("uint", c, colors, 4*(A_Index-1)) ; Place the unsigned int at each offset. + } + + count := DllCall(pixelsearchall3, "ptr", result, "uint", limit, "ptr", this.ptr, "ptr", this.ptr + this.size, "ptr", colors, "uint", color.length, "cdecl ptr") + } + + ; Options 6 & 7 - Creates a high and low struct where each pair is the min and max range. + + if (option == 6) { + high := Buffer(4*color.length) + low := Buffer(4*color.length) + + for c in color { + A_Offset := A_Index - 1 + + r := ((c & 0xFF0000) >> 16) + g := ((c & 0xFF00) >> 8) + b := ((c & 0xFF)) + v := abs(variation) + + NumPut("uchar", 255, high, 4*A_Offset + 3) ; Alpha + NumPut("uchar", min(r+v, 255), high, 4*A_Offset + 2) + NumPut("uchar", min(g+v, 255), high, 4*A_Offset + 1) + NumPut("uchar", min(b+v, 255), high, 4*A_Offset + 0) + + NumPut("uchar", 0, low, 4*A_Offset + 3) ; Alpha + NumPut("uchar", max(r-v, 0), low, 4*A_Offset + 2) + NumPut("uchar", max(g-v, 0), low, 4*A_Offset + 1) + NumPut("uchar", max(b-v, 0), low, 4*A_Offset + 0) + } + + count := DllCall(pixelsearchall4, "ptr", result, "uint", limit, "ptr", this.ptr, "ptr", this.ptr + this.size, "ptr", high, "ptr", low, "uint", color.length, "cdecl ptr") + } + + if (option == 7) { + high := Buffer(4*color.length) + low := Buffer(4*color.length) + + for c in color { + A_Offset := A_Index - 1 + + r := ((c & 0xFF0000) >> 16) + g := ((c & 0xFF00) >> 8) + b := ((c & 0xFF)) + vr := abs(variation[1]) + vg := abs(variation[2]) + vb := abs(variation[3]) + + NumPut("uchar", 255, high, 4*A_Offset + 3) ; Alpha + NumPut("uchar", min(r + vr, 255), high, 4*A_Offset + 2) + NumPut("uchar", min(g + vg, 255), high, 4*A_Offset + 1) + NumPut("uchar", min(b + vb, 255), high, 4*A_Offset + 0) + + NumPut("uchar", 0, low, 4*A_Offset + 3) ; Alpha + NumPut("uchar", max(r - vr, 0), low, 4*A_Offset + 2) + NumPut("uchar", max(g - vg, 0), low, 4*A_Offset + 1) + NumPut("uchar", max(b - vb, 0), low, 4*A_Offset + 0) + } + + count := DllCall(pixelsearchall4, "ptr", result, "uint", limit, "ptr", this.ptr, "ptr", this.ptr + this.size, "ptr", high, "ptr", low, "uint", color.length, "cdecl ptr") + } + + ; If the default 256 results is exceeded, run the machine code again. + if (count > limit) { + limit := count + goto redo } ; Check if any matches are found. - if (count = 0) + if (count == 0) return False ; Create an array of [x, y] coordinates. xys := [] loop count { - byte := NumGet(result, A_PtrSize*(A_Index-1), "ptr") + byte := NumGet(result, A_PtrSize * (A_Index-1), "ptr") offset := (byte - this.ptr) // 4 - xy := [mod(offset, this.width), offset // this.width] - xys.push(xy) + xys.push([mod(offset, this.width), offset // this.width]) } return xys } From 8f86d7cf2b5f3f8dfe490713a8f7075bbc7732f8 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 22 Sep 2023 20:35:03 -0400 Subject: [PATCH 453/492] rename byte to address cause byte doesn't make sense when the return is a pointer to an unsigned int --- ImagePut (for v1).ahk | 22 +++++++++++----------- ImagePut.ahk | 20 ++++++++++---------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index ecb87c8e..d9d6c42a 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2465,7 +2465,7 @@ class ImagePut { ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. if (option == 1) - byte := DllCall(pixelsearch1, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "cdecl ptr") + address :=DllCall(pixelsearch1, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "cdecl ptr") if (option == 2) { r := ((color & 0xFF0000) >> 16) @@ -2473,7 +2473,7 @@ class ImagePut { b := ((color & 0xFF)) v := abs(variation) - byte := DllCall(pixelsearch2, "ptr", this.ptr, "ptr", this.ptr + this.size + address :=DllCall(pixelsearch2, "ptr", this.ptr, "ptr", this.ptr + this.size , "uchar", min(r+v, 255) , "uchar", max(r-v, 0) , "uchar", min(g+v, 255) @@ -2491,7 +2491,7 @@ class ImagePut { vg := abs(variation[2]) vb := abs(variation[3]) - byte := DllCall(pixelsearch2, "ptr", this.ptr, "ptr", this.ptr + this.size + address :=DllCall(pixelsearch2, "ptr", this.ptr, "ptr", this.ptr + this.size , "uchar", min(r + vr, 255) , "uchar", max(r - vr, 0) , "uchar", min(g + vg, 255) @@ -2502,7 +2502,7 @@ class ImagePut { } if (option == 4) - byte := DllCall(pixelsearch2, "ptr", this.ptr, "ptr", this.ptr + this.size + address :=DllCall(pixelsearch2, "ptr", this.ptr, "ptr", this.ptr + this.size , "uchar", min(max(variation[1], variation[2]), 255) , "uchar", max(min(variation[1], variation[2]), 0) , "uchar", min(max(variation[3], variation[4]), 255) @@ -2521,7 +2521,7 @@ class ImagePut { NumPut(c, colors, 4*(A_Index-1), "uint") ; Place the unsigned int at each offset. } - byte := DllCall(pixelsearch3, "ptr", this.ptr, "ptr", this.ptr + this.size, "ptr", &colors, "uint", color.length(), "cdecl ptr") + address :=DllCall(pixelsearch3, "ptr", this.ptr, "ptr", this.ptr + this.size, "ptr", &colors, "uint", color.length(), "cdecl ptr") } ; Options 6 & 7 - Creates a high and low struct where each pair is the min and max range. @@ -2549,7 +2549,7 @@ class ImagePut { NumPut(max(b-v, 0), low, 4*A_Offset + 0, "uchar") } - byte := DllCall(pixelsearch4, "ptr", this.ptr, "ptr", this.ptr + this.size, "ptr", &high, "ptr", &low, "uint", color.length(), "cdecl ptr") + address :=DllCall(pixelsearch4, "ptr", this.ptr, "ptr", this.ptr + this.size, "ptr", &high, "ptr", &low, "uint", color.length(), "cdecl ptr") } if (option == 7) { @@ -2577,7 +2577,7 @@ class ImagePut { NumPut(max(b - vb, 0), low, 4*A_Offset + 0, "uchar") } - byte := DllCall(pixelsearch4, "ptr", this.ptr, "ptr", this.ptr + this.size, "ptr", &high, "ptr", &low, "uint", color.length(), "cdecl ptr") + address :=DllCall(pixelsearch4, "ptr", this.ptr, "ptr", this.ptr + this.size, "ptr", &high, "ptr", &low, "uint", color.length(), "cdecl ptr") } ; Compare the address to the out-of-bounds limit. @@ -2799,13 +2799,13 @@ class ImagePut { } ; Check if any matches are found. - if (count = 0) + if (count == 0) return False ; Create an array of [x, y] coordinates. xys := [] loop % count { - byte := NumGet(result, A_PtrSize*(A_Index-1), "ptr") + address :=NumGet(result, A_PtrSize*(A_Index-1), "ptr") offset := (byte - this.ptr) // 4 xys.push([mod(offset, this.width), offset // this.width]) } @@ -2827,7 +2827,7 @@ class ImagePut { image := ImagePutBuffer(image) ; Search for the address of the first matching image. - byte := DllCall(code, "ptr", this.ptr, "uint", this.width, "uint", this.height + address :=DllCall(code, "ptr", this.ptr, "uint", this.width, "uint", this.height , "ptr", image.ptr, "uint", image.width, "uint", image.height, "cdecl ptr") ; Compare the address to the out-of-bounds limit. @@ -2876,7 +2876,7 @@ class ImagePut { ; Create an array of [x, y] coordinates. xys := [] loop % count { - byte := NumGet(result, A_PtrSize*(A_Index-1), "ptr") + address :=NumGet(result, A_PtrSize*(A_Index-1), "ptr") offset := (byte - this.ptr) // 4 xy := [mod(offset, this.width), offset // this.width] xys.push(xy) diff --git a/ImagePut.ahk b/ImagePut.ahk index b1700765..1252f362 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2465,7 +2465,7 @@ class ImagePut { ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. if (option == 1) - byte := DllCall(pixelsearch1, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "cdecl ptr") + address := DllCall(pixelsearch1, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "cdecl ptr") if (option == 2) { r := ((color & 0xFF0000) >> 16) @@ -2473,7 +2473,7 @@ class ImagePut { b := ((color & 0xFF)) v := abs(variation) - byte := DllCall(pixelsearch2, "ptr", this.ptr, "ptr", this.ptr + this.size + address := DllCall(pixelsearch2, "ptr", this.ptr, "ptr", this.ptr + this.size , "uchar", min(r+v, 255) , "uchar", max(r-v, 0) , "uchar", min(g+v, 255) @@ -2491,7 +2491,7 @@ class ImagePut { vg := abs(variation[2]) vb := abs(variation[3]) - byte := DllCall(pixelsearch2, "ptr", this.ptr, "ptr", this.ptr + this.size + address := DllCall(pixelsearch2, "ptr", this.ptr, "ptr", this.ptr + this.size , "uchar", min(r + vr, 255) , "uchar", max(r - vr, 0) , "uchar", min(g + vg, 255) @@ -2502,7 +2502,7 @@ class ImagePut { } if (option == 4) - byte := DllCall(pixelsearch2, "ptr", this.ptr, "ptr", this.ptr + this.size + address := DllCall(pixelsearch2, "ptr", this.ptr, "ptr", this.ptr + this.size , "uchar", min(max(variation[1], variation[2]), 255) , "uchar", max(min(variation[1], variation[2]), 0) , "uchar", min(max(variation[3], variation[4]), 255) @@ -2521,7 +2521,7 @@ class ImagePut { NumPut("uint", c, colors, 4*(A_Index-1)) ; Place the unsigned int at each offset. } - byte := DllCall(pixelsearch3, "ptr", this.ptr, "ptr", this.ptr + this.size, "ptr", colors, "uint", color.length, "cdecl ptr") + address := DllCall(pixelsearch3, "ptr", this.ptr, "ptr", this.ptr + this.size, "ptr", colors, "uint", color.length, "cdecl ptr") } ; Options 6 & 7 - Creates a high and low struct where each pair is the min and max range. @@ -2549,7 +2549,7 @@ class ImagePut { NumPut("uchar", max(b-v, 0), low, 4*A_Offset + 0) } - byte := DllCall(pixelsearch4, "ptr", this.ptr, "ptr", this.ptr + this.size, "ptr", high, "ptr", low, "uint", color.length, "cdecl ptr") + address := DllCall(pixelsearch4, "ptr", this.ptr, "ptr", this.ptr + this.size, "ptr", high, "ptr", low, "uint", color.length, "cdecl ptr") } if (option == 7) { @@ -2577,7 +2577,7 @@ class ImagePut { NumPut("uchar", max(b - vb, 0), low, 4*A_Offset + 0) } - byte := DllCall(pixelsearch4, "ptr", this.ptr, "ptr", this.ptr + this.size, "ptr", high, "ptr", low, "uint", color.length, "cdecl ptr") + address := DllCall(pixelsearch4, "ptr", this.ptr, "ptr", this.ptr + this.size, "ptr", high, "ptr", low, "uint", color.length, "cdecl ptr") } ; Compare the address to the out-of-bounds limit. @@ -2805,7 +2805,7 @@ class ImagePut { ; Create an array of [x, y] coordinates. xys := [] loop count { - byte := NumGet(result, A_PtrSize * (A_Index-1), "ptr") + address := NumGet(result, A_PtrSize * (A_Index-1), "ptr") offset := (byte - this.ptr) // 4 xys.push([mod(offset, this.width), offset // this.width]) } @@ -2827,7 +2827,7 @@ class ImagePut { image := ImagePutBuffer(image) ; Search for the address of the first matching image. - byte := DllCall(code, "ptr", this.ptr, "uint", this.width, "uint", this.height + address := DllCall(code, "ptr", this.ptr, "uint", this.width, "uint", this.height , "ptr", image.ptr, "uint", image.width, "uint", image.height, "cdecl ptr") ; Compare the address to the out-of-bounds limit. @@ -2876,7 +2876,7 @@ class ImagePut { ; Create an array of [x, y] coordinates. xys := [] loop count { - byte := NumGet(result, A_PtrSize*(A_Index-1), "ptr") + address := NumGet(result, A_PtrSize*(A_Index-1), "ptr") offset := (byte - this.ptr) // 4 xy := [mod(offset, this.width), offset // this.width] xys.push(xy) From 257bcca5571c0df5fd8893e2e3be54d11c59d975 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 22 Sep 2023 20:35:59 -0400 Subject: [PATCH 454/492] spacing --- ImagePut (for v1).ahk | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index d9d6c42a..4a1ba00e 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2465,7 +2465,7 @@ class ImagePut { ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. if (option == 1) - address :=DllCall(pixelsearch1, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "cdecl ptr") + address := DllCall(pixelsearch1, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "cdecl ptr") if (option == 2) { r := ((color & 0xFF0000) >> 16) @@ -2473,7 +2473,7 @@ class ImagePut { b := ((color & 0xFF)) v := abs(variation) - address :=DllCall(pixelsearch2, "ptr", this.ptr, "ptr", this.ptr + this.size + address := DllCall(pixelsearch2, "ptr", this.ptr, "ptr", this.ptr + this.size , "uchar", min(r+v, 255) , "uchar", max(r-v, 0) , "uchar", min(g+v, 255) @@ -2491,7 +2491,7 @@ class ImagePut { vg := abs(variation[2]) vb := abs(variation[3]) - address :=DllCall(pixelsearch2, "ptr", this.ptr, "ptr", this.ptr + this.size + address := DllCall(pixelsearch2, "ptr", this.ptr, "ptr", this.ptr + this.size , "uchar", min(r + vr, 255) , "uchar", max(r - vr, 0) , "uchar", min(g + vg, 255) @@ -2502,7 +2502,7 @@ class ImagePut { } if (option == 4) - address :=DllCall(pixelsearch2, "ptr", this.ptr, "ptr", this.ptr + this.size + address := DllCall(pixelsearch2, "ptr", this.ptr, "ptr", this.ptr + this.size , "uchar", min(max(variation[1], variation[2]), 255) , "uchar", max(min(variation[1], variation[2]), 0) , "uchar", min(max(variation[3], variation[4]), 255) @@ -2521,7 +2521,7 @@ class ImagePut { NumPut(c, colors, 4*(A_Index-1), "uint") ; Place the unsigned int at each offset. } - address :=DllCall(pixelsearch3, "ptr", this.ptr, "ptr", this.ptr + this.size, "ptr", &colors, "uint", color.length(), "cdecl ptr") + address := DllCall(pixelsearch3, "ptr", this.ptr, "ptr", this.ptr + this.size, "ptr", &colors, "uint", color.length(), "cdecl ptr") } ; Options 6 & 7 - Creates a high and low struct where each pair is the min and max range. @@ -2549,7 +2549,7 @@ class ImagePut { NumPut(max(b-v, 0), low, 4*A_Offset + 0, "uchar") } - address :=DllCall(pixelsearch4, "ptr", this.ptr, "ptr", this.ptr + this.size, "ptr", &high, "ptr", &low, "uint", color.length(), "cdecl ptr") + address := DllCall(pixelsearch4, "ptr", this.ptr, "ptr", this.ptr + this.size, "ptr", &high, "ptr", &low, "uint", color.length(), "cdecl ptr") } if (option == 7) { @@ -2577,7 +2577,7 @@ class ImagePut { NumPut(max(b - vb, 0), low, 4*A_Offset + 0, "uchar") } - address :=DllCall(pixelsearch4, "ptr", this.ptr, "ptr", this.ptr + this.size, "ptr", &high, "ptr", &low, "uint", color.length(), "cdecl ptr") + address := DllCall(pixelsearch4, "ptr", this.ptr, "ptr", this.ptr + this.size, "ptr", &high, "ptr", &low, "uint", color.length(), "cdecl ptr") } ; Compare the address to the out-of-bounds limit. @@ -2805,7 +2805,7 @@ class ImagePut { ; Create an array of [x, y] coordinates. xys := [] loop % count { - address :=NumGet(result, A_PtrSize*(A_Index-1), "ptr") + address := NumGet(result, A_PtrSize*(A_Index-1), "ptr") offset := (byte - this.ptr) // 4 xys.push([mod(offset, this.width), offset // this.width]) } @@ -2827,7 +2827,7 @@ class ImagePut { image := ImagePutBuffer(image) ; Search for the address of the first matching image. - address :=DllCall(code, "ptr", this.ptr, "uint", this.width, "uint", this.height + address := DllCall(code, "ptr", this.ptr, "uint", this.width, "uint", this.height , "ptr", image.ptr, "uint", image.width, "uint", image.height, "cdecl ptr") ; Compare the address to the out-of-bounds limit. @@ -2876,7 +2876,7 @@ class ImagePut { ; Create an array of [x, y] coordinates. xys := [] loop % count { - address :=NumGet(result, A_PtrSize*(A_Index-1), "ptr") + address := NumGet(result, A_PtrSize*(A_Index-1), "ptr") offset := (byte - this.ptr) // 4 xy := [mod(offset, this.width), offset // this.width] xys.push(xy) From 479febc1937b86f873475470d1e6400a67145a78 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 22 Sep 2023 20:38:55 -0400 Subject: [PATCH 455/492] finish renaming byte to address --- ImagePut (for v1).ahk | 12 ++++++------ ImagePut.ahk | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 4a1ba00e..59d747ce 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2581,11 +2581,11 @@ class ImagePut { } ; Compare the address to the out-of-bounds limit. - if (byte == this.ptr + this.size) + if (address == this.ptr + this.size) return False ; Return an [x, y] array. - offset := (byte - this.ptr) // 4 + offset := (address - this.ptr) // 4 return [mod(offset, this.width), offset // this.width] } @@ -2806,7 +2806,7 @@ class ImagePut { xys := [] loop % count { address := NumGet(result, A_PtrSize*(A_Index-1), "ptr") - offset := (byte - this.ptr) // 4 + offset := (address - this.ptr) // 4 xys.push([mod(offset, this.width), offset // this.width]) } return xys @@ -2831,11 +2831,11 @@ class ImagePut { , "ptr", image.ptr, "uint", image.width, "uint", image.height, "cdecl ptr") ; Compare the address to the out-of-bounds limit. - if (byte == this.ptr + this.size) + if (address == this.ptr + this.size) return False ; Return an [x, y] array. - offset := (byte - this.ptr) // 4 + offset := (address - this.ptr) // 4 return [mod(offset, this.width), offset // this.width] } @@ -2877,7 +2877,7 @@ class ImagePut { xys := [] loop % count { address := NumGet(result, A_PtrSize*(A_Index-1), "ptr") - offset := (byte - this.ptr) // 4 + offset := (address - this.ptr) // 4 xy := [mod(offset, this.width), offset // this.width] xys.push(xy) } diff --git a/ImagePut.ahk b/ImagePut.ahk index 1252f362..64bfe0f3 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2581,11 +2581,11 @@ class ImagePut { } ; Compare the address to the out-of-bounds limit. - if (byte == this.ptr + this.size) + if (address == this.ptr + this.size) return False ; Return an [x, y] array. - offset := (byte - this.ptr) // 4 + offset := (address - this.ptr) // 4 return [mod(offset, this.width), offset // this.width] } @@ -2806,7 +2806,7 @@ class ImagePut { xys := [] loop count { address := NumGet(result, A_PtrSize * (A_Index-1), "ptr") - offset := (byte - this.ptr) // 4 + offset := (address - this.ptr) // 4 xys.push([mod(offset, this.width), offset // this.width]) } return xys @@ -2831,11 +2831,11 @@ class ImagePut { , "ptr", image.ptr, "uint", image.width, "uint", image.height, "cdecl ptr") ; Compare the address to the out-of-bounds limit. - if (byte == this.ptr + this.size) + if (address == this.ptr + this.size) return False ; Return an [x, y] array. - offset := (byte - this.ptr) // 4 + offset := (address - this.ptr) // 4 return [mod(offset, this.width), offset // this.width] } @@ -2877,7 +2877,7 @@ class ImagePut { xys := [] loop count { address := NumGet(result, A_PtrSize*(A_Index-1), "ptr") - offset := (byte - this.ptr) // 4 + offset := (address - this.ptr) // 4 xy := [mod(offset, this.width), offset // this.width] xys.push(xy) } From 349064f4940116329aa5403611bda9ffe949ce95 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 22 Sep 2023 20:47:06 -0400 Subject: [PATCH 456/492] Rename Fix Machine Code --- ImagePut (for v1).ahk | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 59d747ce..84464a5a 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2630,10 +2630,7 @@ class ImagePut { . "0gnYweIICcgPtk0kDQAAAP8J0Q+2VRRmD27oi0UIZg9wzQDB4hAJ0Y1W9GYPbvFmD3DWADnQczkPEAAPEBgPEDhmD97BZg/e2mYP" . "dMFmD3TfD1TDZg92xGYP18iFyXURg8AQ68+KUAI4VCQPcwmDwAQ58HLw6yM6VCQOcvGKUAE4VCQNcug6VCQMcuKKEIn5ONFy2jpU" . "JAty1I1l9FteX13D" - : "QVZBVUFUVVdWU0SLbCRgi0QkaESLdCRwRItUJHhEie6Jx0UPtu0PtsBBweUIRIn1RQ+29kWJ1EWJw0UPtsBEicvB4AhBweAQRQ+2" - . "0kUPtslFCfBECdBBweEQRQnoRAnIQYHIAAAA/2YPbuhIichmQQ9uyEiNSvRmD3DBAGYPcM0AZg927Ug5yHM8DxAgDyjQDyjcZg/e" - . "1GYP3tlmD3TQZg903A9U02YPdtVmRA/XwkWFwHUSSIPAEOvLikgCQTjLcwtIg8AESDnQcu/rHTjZcvGKSAFAOM5y6UA4+XLkighA" - . "OM1y3UQ44XLYW15fXUFcQV1BXsM=") + : "QVRVV1ZTMcBEilwkUIpcJFhAinQkYECKfCRoQIpsJHBEimQkeE05yHM8RYpQAkU403ItQTjacihFilABRDjWch9BOPpyGkWKEEQ41XISRTjicg050HMHQYnCTokE0f/ASYPABOu/W15fXUFcww==") ; C source code - https://godbolt.org/z/xj5seEhba pixelsearchall3 := this.Base64Code((A_PtrSize == 4) @@ -2685,7 +2682,7 @@ class ImagePut { b := ((color & 0xFF)) v := abs(variation) - count := DllCall(pixelsearch2, "ptr", &result, "uint", limit, "ptr", this.ptr, "ptr", this.ptr + this.size + count := DllCall(pixelsearchall2, "ptr", &result, "uint", limit, "ptr", this.ptr, "ptr", this.ptr + this.size , "uchar", min(r+v, 255) , "uchar", max(r-v, 0) , "uchar", min(g+v, 255) @@ -2703,7 +2700,7 @@ class ImagePut { vg := abs(variation[2]) vb := abs(variation[3]) - count := DllCall(pixelsearch2, "ptr", &result, "uint", limit, "ptr", this.ptr, "ptr", this.ptr + this.size + count := DllCall(pixelsearchall2, "ptr", &result, "uint", limit, "ptr", this.ptr, "ptr", this.ptr + this.size , "uchar", min(r + vr, 255) , "uchar", max(r - vr, 0) , "uchar", min(g + vg, 255) @@ -2714,7 +2711,7 @@ class ImagePut { } if (option == 4) - count := DllCall(pixelsearch2, "ptr", &result, "uint", limit, "ptr", this.ptr, "ptr", this.ptr + this.size + count := DllCall(pixelsearchall2, "ptr", &result, "uint", limit, "ptr", this.ptr, "ptr", this.ptr + this.size , "uchar", min(max(variation[1], variation[2]), 255) , "uchar", max(min(variation[1], variation[2]), 0) , "uchar", min(max(variation[3], variation[4]), 255) @@ -2733,7 +2730,7 @@ class ImagePut { NumPut(c, colors, 4*(A_Index-1), "uint") ; Place the unsigned int at each offset. } - count := DllCall(pixelsearch3, "ptr", &result, "uint", limit, "ptr", this.ptr, "ptr", this.ptr + this.size, "ptr", &colors, "uint", color.length(), "cdecl ptr") + count := DllCall(pixelsearchall3, "ptr", &result, "uint", limit, "ptr", this.ptr, "ptr", this.ptr + this.size, "ptr", &colors, "uint", color.length(), "cdecl ptr") } ; Options 6 & 7 - Creates a high and low struct where each pair is the min and max range. @@ -2761,7 +2758,7 @@ class ImagePut { NumPut(max(b-v, 0), low, 4*A_Offset + 0, "uchar") } - count := DllCall(pixelsearch4, "ptr", &result, "uint", limit, "ptr", this.ptr, "ptr", this.ptr + this.size, "ptr", &high, "ptr", &low, "uint", color.length(), "cdecl ptr") + count := DllCall(pixelsearchall4, "ptr", &result, "uint", limit, "ptr", this.ptr, "ptr", this.ptr + this.size, "ptr", &high, "ptr", &low, "uint", color.length(), "cdecl ptr") } if (option == 7) { @@ -2789,7 +2786,7 @@ class ImagePut { NumPut(max(b - vb, 0), low, 4*A_Offset + 0, "uchar") } - count := DllCall(pixelsearch4, "ptr", &result, "uint", limit, "ptr", this.ptr, "ptr", this.ptr + this.size, "ptr", &high, "ptr", &low, "uint", color.length(), "cdecl ptr") + count := DllCall(pixelsearchall4, "ptr", &result, "uint", limit, "ptr", this.ptr, "ptr", this.ptr + this.size, "ptr", &high, "ptr", &low, "uint", color.length(), "cdecl ptr") } ; If the default 256 results is exceeded, run the machine code again. From fed26e4b25c00339ad740563615c0dd817e6dd2d Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 22 Sep 2023 20:52:56 -0400 Subject: [PATCH 457/492] Add machine code for PixelSearchAll (not SIMD) --- ImagePut (for v1).ahk | 47 +++++++++++----------------------------- ImagePut.ahk | 50 +++++++++++-------------------------------- 2 files changed, 26 insertions(+), 71 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 84464a5a..5908b03f 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2619,49 +2619,28 @@ class ImagePut { ; ----------------------- Machine code generated with MCode4GCC using gcc 13.2.0 ----------------------- - ; C source code - https://godbolt.org/z/6jPnc6b5s + ; C source code - https://godbolt.org/z/ahEsGeaxK pixelsearchall1 := this.Base64Code((A_PtrSize == 4) ? "VYnlVotNEItVDFOLRQhmD27RjVr0Zg9wygA52HMbDxAAZg92wWYP1/CF9nUMg8AQ6+g5CHQHg8AEOdBy9VteXcM=" : "McBEi1QkKE05yHMYRTkQdQ050HMHQYnDTokE2f/ASYPABOvjww==") - ; C source code - https://godbolt.org/z/7fv3P6KTb + ; C source code - https://godbolt.org/z/hq55M66fP pixelsearchall2 := this.Base64Code((A_PtrSize == 4) - ? "VWYPduSJ5VdWU4Pk8IPsEIpFFItdEItNGItVHIt1DIt9IIhEJA6KRSSIXCQPD7bbiEwkDcHjEA+2yYhEJAsPtkUgweEIiFQkDA+2" - . "0gnYweIICcgPtk0kDQAAAP8J0Q+2VRRmD27oi0UIZg9wzQDB4hAJ0Y1W9GYPbvFmD3DWADnQczkPEAAPEBgPEDhmD97BZg/e2mYP" - . "dMFmD3TfD1TDZg92xGYP18iFyXURg8AQ68+KUAI4VCQPcwmDwAQ58HLw6yM6VCQOcvGKUAE4VCQNcug6VCQMcuKKEIn5ONFy2jpU" - . "JAty1I1l9FteX13D" - : "QVRVV1ZTMcBEilwkUIpcJFhAinQkYECKfCRoQIpsJHBEimQkeE05yHM8RYpQAkU403ItQTjacihFilABRDjWch9BOPpyGkWKEEQ41XISRTjicg050HMHQYnCTokE0f/ASYPABOu/W15fXUFcww==") + ? "VTHAieVTi1UQi00UOcpzGItdGDkadQw7RQxzBotdCIkUg0CDwgTr5Ftdww==" + : "QVRVV1ZTMcBEilwkUIpcJFhAinQkYECKfCRoQIpsJHBEimQkeE05yHM8RYpQAkU403ItQTjacihFilABRDjWch9BOPpyGkWKEEQ4" + . "1XISRTjicg050HMHQYnCTokE0f/ASYPABOu/W15fXUFcww==") - ; C source code - https://godbolt.org/z/xj5seEhba + ; C source code - https://godbolt.org/z/9jT694Pdn pixelsearchall3 := this.Base64Code((A_PtrSize == 4) - ? "VTHSieVXi00MVlOLXRCLRRQp0A+E5QAAAIP4AXQbg/gCdAtmD25skwhmD3DdAGYPbnSTBGYPcNYAZg9uPJNmD3DPAIP4AXR6g/gC" - . "jXH0i0UIdGM58HM2DxAADyjgZg924WYP1/yF/w+FiQAAAA8o4mYPduBmD9f8hf91emYPdsNmD9f4hf91boPAEOvGg8ID6Xn///8P" - . "EAAPKOFmD3bgZg/X/IX/dU9mD3bCZg/X+IX/dUODwBA58HLbg8IC6Uz///+LRQiNcfQ58HMUDxAAZg92wWYP1/iF/3Ubg8AQ6+hC" - . "6Sj///+LNJM5MHQTQjtVFHXzg8AEOchzBjHS6/CJyFteX13D" - : "U0mJykiJ0THSTI1Z9ESJyCnQD4T2AAAASGPag/gBdB2D+AJ0DGZBD25smAhmD3DdAGZBD25smARmD3DVAGZBD24MmGYPcMkAg/gB" - . "dH+D+AJMidB0akw52HM7DxAADyjgZg924WYP19yF2w+FlQAAAA8o4mYPduBmD9fchdsPhYIAAABmD3bDZg/X2IXbdXZIg8AQ68CD" - . "wgPpcP///w8QAA8o4WYPduBmD9fchdt1VmYPdsJmD9fYhdt1SkiDwBBMOdhy2YPCAulB////TInQTDnYcxUPEABmD3bBZg/X2IXb" - . "dSJIg8AQ6+b/wukd////SP/CQYtckPw5GHQVRDnKcu9Ig8AESDnIcwcx0uvuSInIW8M=") + ? "VYnlV4tFHItVEFZTi10YjTSDMcA7VRRzIonZOfF0F4s5OTp1DDtFDHMGi30IiRSHQIPBBOvlg8IE69lbXl9dww==" + : "UzHATItcJDBNOchzKkUx0kQ7VCQ4cxpDixyTQTkYdQw50HMGicNMiQTZ/8BJ/8Lr30mDwATr0VvD") - ; C source code - https://godbolt.org/z/W54vWW7Gz + ; C source code - https://godbolt.org/z/MhdaWq6fK pixelsearchall4 := this.Base64Code((A_PtrSize == 4) - ? "VTHSieVXVlOD5PCD7CCLdRCLTRSLRRgp0A+EDAIAAIP4AXQ6g/gCdB9mD25klghmD3DsAA8pbCQQZg9ubJEIZg9w3QAPKRwkZg9u" - . "ZJYEZg9uVJEEZg9w3ABmD3DqAGYPbiSWZg9uNJFmD3DUAGYPcOYAg/gBD4QdAQAAg/gCi0UID4SlAAAAi30MZg929o1f9DnYD4OL" - . "AAAADxAADyj6DyjIZg/e+GYP3sxmD3T6Zg90yA9Uz2YPds5mD9f5hf8PhSgBAAAPKMsPKPhmD97IZg/e/WYPdMtmD3T4D1TPZg92" - . "zmYP1/mF/w+F/wAAAA8oPCQPKEwkEGYP3vhmD97IZg90TCQQZg90xw9UyGYPds5mD9f5hf8PhdEAAACDwBDpbf///4PCA+no/v//" - . "i10MZg929oPrDDnYc1YPEAAPKPgPKMhmD978Zg/eymYPdMpmD3T4D1TPZg92zmYP1/mF/w+FhwAAAA8o+A8oy2YP3shmD979Zg90" - . "y2YPdMcPVMhmD3bOZg/X+YX/dWKDwBDrpoPCAul8/v//i30Mi0UIZg929o1f9DnYcy0PEAgPEAAPEDhmD97MZg/ewmYPdMJmD3TP" - . "D1TBZg92xmYP1/iF/3Ucg8AQ689C6Tj+//+J+zhclgJzIkI7VRh18oPABDtFDHM8ilABD7Z4AohUJBCKEIgUJDHS6986XJECctiK" - . "XCQQOFyWAXLOOlyRAXLIihwkOByWcsA6HJFyu+sDi0UMjWX0W15fXcM=" - : "VlNIg+xIDyk0JA8pfCQQRA8pRCQgRA8pTCQwi5wkgAAAAEmJykiJ0THSSI1x9EGJ20Ep0w+EEwIAAEhjwkGD+wF0NkGD+wJ0GGZB" - . "D250gAhmQQ9ubIEIZg9w5gBmD3D1AGZBD25cgARmQQ9ubIEEZg9w0wBmD3DtAGZBD24cgGZFD3bAZg9wywBmQQ9uHIFMidBmD3Db" - . "AEGD+wEPhFcBAABBg/sCD4QOAQAASDnwD4ObAAAADxAARA8oyQ8o+GZED97IZg/e+2ZED3TJZg90+EEPVPlmQQ92+GZED9ffRYXb" - . "D4UvAQAADyj6RA8oyGYP3vhmRA/ezWYPdPpmRA90yEEPVPlmQQ92+GZED9ffRYXbD4X/AAAARA8oyA8o/GYP3vhmRA/ezmYPdPxm" - . "QQ90wQ9Ux2ZBD3bAZkQP19hFhdsPhdAAAABIg8AQ6Vz///+DwgPp1/7//w8QAEQPKMgPKPhmRA/ey2YP3vlmD3T5ZkQPdMhBD1T5" - . "ZkEPdvhmRA/X30WF2w+FjAAAAEQPKMgPKPpmD974ZkQP3s1mD3T6ZkEPdMEPVMdmQQ92wGZED9fYRYXbdWFIg8AQSDnwcpmDwgLp" - . "aP7//w8QOEQPKM8PKMdmRA/ey2YP3sFmD3TBZkEPdPkPVMdmQQ92wGZED9fYRYXbdSJIg8AQSDnwcsn/wukq/v//RThUkAJzH0j/" - . "wjnacvJIg8AESDnIczVEilACRIpYATHSQIow6+RFOlSRAnLaRThckAFy00U6XJEBcsxBODSQcsZBOjSRcsDrA0iJyA8oNCQPKHwk" - . "EEQPKEQkIEQPKEwkMEiDxEhbXsM=") + ? "VYnlV1ZTUYtVEDHJi30Yi3UcO1UUc1eKQgKIRfOKQgGIRfKKAohF8THAO0UgdDqKXfM4XIcCci46XIYCciiKXfI4XIcBch86XIYB" + . "chmKXfE4HIdyETochnIMO00McwaLXQiJFItBQOvBg8IE66RaichbXl9dww==" + : "QVVBVFVXVlNIi1wkWItEJGhMjSSDQYnTSYnKMdJNOchzWEGKcAJBingBSInYQYooSItMJGBMOeB0OkA4cAJyKkA6cQJyJEA4eAFy" + . "HkA6eQFyGEA4KHITQDopcg5EOdpzB0GJ1U+JBOr/wkiDwARIg8EE68FJg8AE66OJ0FteX11BXEFdww==") ; ------------------------------------------------------------------------------------------------------ diff --git a/ImagePut.ahk b/ImagePut.ahk index 64bfe0f3..d1957e79 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2619,52 +2619,28 @@ class ImagePut { ; ----------------------- Machine code generated with MCode4GCC using gcc 13.2.0 ----------------------- - ; C source code - https://godbolt.org/z/6jPnc6b5s + ; C source code - https://godbolt.org/z/ahEsGeaxK pixelsearchall1 := this.Base64Code((A_PtrSize == 4) ? "VYnlVotNEItVDFOLRQhmD27RjVr0Zg9wygA52HMbDxAAZg92wWYP1/CF9nUMg8AQ6+g5CHQHg8AEOdBy9VteXcM=" : "McBEi1QkKE05yHMYRTkQdQ050HMHQYnDTokE2f/ASYPABOvjww==") - ; C source code - https://godbolt.org/z/7fv3P6KTb + ; C source code - https://godbolt.org/z/hq55M66fP pixelsearchall2 := this.Base64Code((A_PtrSize == 4) - ? "VWYPduSJ5VdWU4Pk8IPsEIpFFItdEItNGItVHIt1DIt9IIhEJA6KRSSIXCQPD7bbiEwkDcHjEA+2yYhEJAsPtkUgweEIiFQkDA+2" - . "0gnYweIICcgPtk0kDQAAAP8J0Q+2VRRmD27oi0UIZg9wzQDB4hAJ0Y1W9GYPbvFmD3DWADnQczkPEAAPEBgPEDhmD97BZg/e2mYP" - . "dMFmD3TfD1TDZg92xGYP18iFyXURg8AQ68+KUAI4VCQPcwmDwAQ58HLw6yM6VCQOcvGKUAE4VCQNcug6VCQMcuKKEIn5ONFy2jpU" - . "JAty1I1l9FteX13D" - : "QVZBVUFUVVdWU0SLbCRgi0QkaESLdCRwRItUJHhEie6Jx0UPtu0PtsBBweUIRIn1RQ+29kWJ1EWJw0UPtsBEicvB4AhBweAQRQ+2" - . "0kUPtslFCfBECdBBweEQRQnoRAnIQYHIAAAA/2YPbuhIichmQQ9uyEiNSvRmD3DBAGYPcM0AZg927Ug5yHM8DxAgDyjQDyjcZg/e" - . "1GYP3tlmD3TQZg903A9U02YPdtVmRA/XwkWFwHUSSIPAEOvLikgCQTjLcwtIg8AESDnQcu/rHTjZcvGKSAFAOM5y6UA4+XLkighA" - . "OM1y3UQ44XLYW15fXUFcQV1BXsM=") + ? "VTHAieVTi1UQi00UOcpzGItdGDkadQw7RQxzBotdCIkUg0CDwgTr5Ftdww==" + : "QVRVV1ZTMcBEilwkUIpcJFhAinQkYECKfCRoQIpsJHBEimQkeE05yHM8RYpQAkU403ItQTjacihFilABRDjWch9BOPpyGkWKEEQ4" + . "1XISRTjicg050HMHQYnCTokE0f/ASYPABOu/W15fXUFcww==") - ; C source code - https://godbolt.org/z/xj5seEhba + ; C source code - https://godbolt.org/z/9jT694Pdn pixelsearchall3 := this.Base64Code((A_PtrSize == 4) - ? "VTHSieVXi00MVlOLXRCLRRQp0A+E5QAAAIP4AXQbg/gCdAtmD25skwhmD3DdAGYPbnSTBGYPcNYAZg9uPJNmD3DPAIP4AXR6g/gC" - . "jXH0i0UIdGM58HM2DxAADyjgZg924WYP1/yF/w+FiQAAAA8o4mYPduBmD9f8hf91emYPdsNmD9f4hf91boPAEOvGg8ID6Xn///8P" - . "EAAPKOFmD3bgZg/X/IX/dU9mD3bCZg/X+IX/dUODwBA58HLbg8IC6Uz///+LRQiNcfQ58HMUDxAAZg92wWYP1/iF/3Ubg8AQ6+hC" - . "6Sj///+LNJM5MHQTQjtVFHXzg8AEOchzBjHS6/CJyFteX13D" - : "U0mJykiJ0THSTI1Z9ESJyCnQD4T2AAAASGPag/gBdB2D+AJ0DGZBD25smAhmD3DdAGZBD25smARmD3DVAGZBD24MmGYPcMkAg/gB" - . "dH+D+AJMidB0akw52HM7DxAADyjgZg924WYP19yF2w+FlQAAAA8o4mYPduBmD9fchdsPhYIAAABmD3bDZg/X2IXbdXZIg8AQ68CD" - . "wgPpcP///w8QAA8o4WYPduBmD9fchdt1VmYPdsJmD9fYhdt1SkiDwBBMOdhy2YPCAulB////TInQTDnYcxUPEABmD3bBZg/X2IXb" - . "dSJIg8AQ6+b/wukd////SP/CQYtckPw5GHQVRDnKcu9Ig8AESDnIcwcx0uvuSInIW8M=") + ? "VYnlV4tFHItVEFZTi10YjTSDMcA7VRRzIonZOfF0F4s5OTp1DDtFDHMGi30IiRSHQIPBBOvlg8IE69lbXl9dww==" + : "UzHATItcJDBNOchzKkUx0kQ7VCQ4cxpDixyTQTkYdQw50HMGicNMiQTZ/8BJ/8Lr30mDwATr0VvD") - ; C source code - https://godbolt.org/z/W54vWW7Gz + ; C source code - https://godbolt.org/z/MhdaWq6fK pixelsearchall4 := this.Base64Code((A_PtrSize == 4) - ? "VTHSieVXVlOD5PCD7CCLdRCLTRSLRRgp0A+EDAIAAIP4AXQ6g/gCdB9mD25klghmD3DsAA8pbCQQZg9ubJEIZg9w3QAPKRwkZg9u" - . "ZJYEZg9uVJEEZg9w3ABmD3DqAGYPbiSWZg9uNJFmD3DUAGYPcOYAg/gBD4QdAQAAg/gCi0UID4SlAAAAi30MZg929o1f9DnYD4OL" - . "AAAADxAADyj6DyjIZg/e+GYP3sxmD3T6Zg90yA9Uz2YPds5mD9f5hf8PhSgBAAAPKMsPKPhmD97IZg/e/WYPdMtmD3T4D1TPZg92" - . "zmYP1/mF/w+F/wAAAA8oPCQPKEwkEGYP3vhmD97IZg90TCQQZg90xw9UyGYPds5mD9f5hf8PhdEAAACDwBDpbf///4PCA+no/v//" - . "i10MZg929oPrDDnYc1YPEAAPKPgPKMhmD978Zg/eymYPdMpmD3T4D1TPZg92zmYP1/mF/w+FhwAAAA8o+A8oy2YP3shmD979Zg90" - . "y2YPdMcPVMhmD3bOZg/X+YX/dWKDwBDrpoPCAul8/v//i30Mi0UIZg929o1f9DnYcy0PEAgPEAAPEDhmD97MZg/ewmYPdMJmD3TP" - . "D1TBZg92xmYP1/iF/3Ucg8AQ689C6Tj+//+J+zhclgJzIkI7VRh18oPABDtFDHM8ilABD7Z4AohUJBCKEIgUJDHS6986XJECctiK" - . "XCQQOFyWAXLOOlyRAXLIihwkOByWcsA6HJFyu+sDi0UMjWX0W15fXcM=" - : "VlNIg+xIDyk0JA8pfCQQRA8pRCQgRA8pTCQwi5wkgAAAAEmJykiJ0THSSI1x9EGJ20Ep0w+EEwIAAEhjwkGD+wF0NkGD+wJ0GGZB" - . "D250gAhmQQ9ubIEIZg9w5gBmD3D1AGZBD25cgARmQQ9ubIEEZg9w0wBmD3DtAGZBD24cgGZFD3bAZg9wywBmQQ9uHIFMidBmD3Db" - . "AEGD+wEPhFcBAABBg/sCD4QOAQAASDnwD4ObAAAADxAARA8oyQ8o+GZED97IZg/e+2ZED3TJZg90+EEPVPlmQQ92+GZED9ffRYXb" - . "D4UvAQAADyj6RA8oyGYP3vhmRA/ezWYPdPpmRA90yEEPVPlmQQ92+GZED9ffRYXbD4X/AAAARA8oyA8o/GYP3vhmRA/ezmYPdPxm" - . "QQ90wQ9Ux2ZBD3bAZkQP19hFhdsPhdAAAABIg8AQ6Vz///+DwgPp1/7//w8QAEQPKMgPKPhmRA/ey2YP3vlmD3T5ZkQPdMhBD1T5" - . "ZkEPdvhmRA/X30WF2w+FjAAAAEQPKMgPKPpmD974ZkQP3s1mD3T6ZkEPdMEPVMdmQQ92wGZED9fYRYXbdWFIg8AQSDnwcpmDwgLp" - . "aP7//w8QOEQPKM8PKMdmRA/ey2YP3sFmD3TBZkEPdPkPVMdmQQ92wGZED9fYRYXbdSJIg8AQSDnwcsn/wukq/v//RThUkAJzH0j/" - . "wjnacvJIg8AESDnIczVEilACRIpYATHSQIow6+RFOlSRAnLaRThckAFy00U6XJEBcsxBODSQcsZBOjSRcsDrA0iJyA8oNCQPKHwk" - . "EEQPKEQkIEQPKEwkMEiDxEhbXsM=") + ? "VYnlV1ZTUYtVEDHJi30Yi3UcO1UUc1eKQgKIRfOKQgGIRfKKAohF8THAO0UgdDqKXfM4XIcCci46XIYCciiKXfI4XIcBch86XIYB" + . "chmKXfE4HIdyETochnIMO00McwaLXQiJFItBQOvBg8IE66RaichbXl9dww==" + : "QVVBVFVXVlNIi1wkWItEJGhMjSSDQYnTSYnKMdJNOchzWEGKcAJBingBSInYQYooSItMJGBMOeB0OkA4cAJyKkA6cQJyJEA4eAFy" + . "HkA6eQFyGEA4KHITQDopcg5EOdpzB0GJ1U+JBOr/wkiDwARIg8EE68FJg8AE66OJ0FteX11BXEFdww==") ; ------------------------------------------------------------------------------------------------------ From 472d597f3db0d77bbf88142c38d6df1dc201d9a6 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 22 Sep 2023 20:53:28 -0400 Subject: [PATCH 458/492] C source files add pixelsearchall1, 2, 3, and 4 --- source/pixelsearchall1.c | 4 ++-- source/pixelsearchall2.c | 4 ++-- source/pixelsearchall3.c | 13 +++++++++++++ source/pixelsearchall4.c | 28 ++++++++++++++++++++++++++++ 4 files changed, 45 insertions(+), 4 deletions(-) create mode 100644 source/pixelsearchall3.c create mode 100644 source/pixelsearchall4.c diff --git a/source/pixelsearchall1.c b/source/pixelsearchall1.c index bc555528..faf1f39d 100644 --- a/source/pixelsearchall1.c +++ b/source/pixelsearchall1.c @@ -1,8 +1,8 @@ -unsigned int pixelsearchall1(unsigned int ** result, unsigned int capacity, unsigned int * start, unsigned int * end, unsigned int color) { +unsigned int pixelsearchall1(unsigned int ** result, unsigned int limit, unsigned int * start, unsigned int * end, unsigned int color) { unsigned int count = 0; while (start < end) { if (*start == color) { - if (count < capacity) + if (count < limit) *(result + count) = start; count++; } diff --git a/source/pixelsearchall2.c b/source/pixelsearchall2.c index 92a118e0..fa6048b3 100644 --- a/source/pixelsearchall2.c +++ b/source/pixelsearchall2.c @@ -1,4 +1,4 @@ -unsigned int pixelsearchall2(unsigned int ** result, unsigned int capacity, unsigned int * start, unsigned int * end, unsigned char rh, unsigned char rl, unsigned char gh, unsigned char gl, unsigned char bh, unsigned char bl) { +unsigned int pixelsearchall2(unsigned int ** result, unsigned int limit, unsigned int * start, unsigned int * end, unsigned char rh, unsigned char rl, unsigned char gh, unsigned char gl, unsigned char bh, unsigned char bl) { unsigned int count = 0; unsigned char r, g, b; while (start < end) { @@ -6,7 +6,7 @@ unsigned int pixelsearchall2(unsigned int ** result, unsigned int capacity, unsi g = *((unsigned char *) start + 1); b = *((unsigned char *) start + 0); if (rh >= r && r >= rl && gh >= g && g >= gl && bh >= b && b >= bl) { - if (count < capacity) + if (count < limit) *(result + count) = start; count++; } diff --git a/source/pixelsearchall3.c b/source/pixelsearchall3.c new file mode 100644 index 00000000..19ff436f --- /dev/null +++ b/source/pixelsearchall3.c @@ -0,0 +1,13 @@ +unsigned int pixelsearchall3(unsigned int ** result, unsigned int limit, unsigned int * start, unsigned int * end, unsigned int * colors, unsigned int length) { + unsigned int count = 0; + while (start < end) { + for (int i = 0; i < length; i++) + if (*start == colors[i]) { + if (count < limit) + *(result + count) = start; + count++; + } + start++; + } + return count; +} \ No newline at end of file diff --git a/source/pixelsearchall4.c b/source/pixelsearchall4.c new file mode 100644 index 00000000..92a48fbe --- /dev/null +++ b/source/pixelsearchall4.c @@ -0,0 +1,28 @@ +unsigned int pixelsearchall4(unsigned int ** result, unsigned int limit, unsigned int * start, unsigned int * end, unsigned int * high, unsigned int * low, unsigned int length) { + unsigned int count = 0; + unsigned char r, g, b, rh, gh, bh, rl, gl, bl; + while (start < end) { + + r = *((unsigned char *) start + 2); + g = *((unsigned char *) start + 1); + b = *((unsigned char *) start + 0); + + for (int i = 0; i < length; i++) { + + rh = *((unsigned char *) high + 4*i + 2); + gh = *((unsigned char *) high + 4*i + 1); + bh = *((unsigned char *) high + 4*i + 0); + rl = *((unsigned char *) low + 4*i + 2); + gl = *((unsigned char *) low + 4*i + 1); + bl = *((unsigned char *) low + 4*i + 0); + + if (rh >= r && r >= rl && gh >= g && g >= gl && bh >= b && b >= bl) { + if (count < limit) + *(result + count) = start; + count++; + } + } + start++; + } + return count; +} \ No newline at end of file From 4118962789b3ebd7dee317e0b34eea5e244d809b Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 22 Sep 2023 23:47:31 -0400 Subject: [PATCH 459/492] C source files Added pixelsearchall1x, 2x, 3x, 4x Added a note about the x64 calling convention I decided not to add that to every single c file. --- source/__Note__.txt | 3 + source/pixelsearchall1x.c | 53 +++++++++++++ source/pixelsearchall2x.c | 73 ++++++++++++++++++ source/pixelsearchall3x.c | 108 ++++++++++++++++++++++++++ source/pixelsearchall4x.c | 157 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 394 insertions(+) create mode 100644 source/__Note__.txt create mode 100644 source/pixelsearchall1x.c create mode 100644 source/pixelsearchall2x.c create mode 100644 source/pixelsearchall3x.c create mode 100644 source/pixelsearchall4x.c diff --git a/source/__Note__.txt b/source/__Note__.txt new file mode 100644 index 00000000..78ec7c32 --- /dev/null +++ b/source/__Note__.txt @@ -0,0 +1,3 @@ +Use this at the top of your code to get the x64 calling convention + +__attribute__((ms_abi)) \ No newline at end of file diff --git a/source/pixelsearchall1x.c b/source/pixelsearchall1x.c new file mode 100644 index 00000000..95614592 --- /dev/null +++ b/source/pixelsearchall1x.c @@ -0,0 +1,53 @@ +#include + +unsigned int pixelsearchall1(unsigned int ** result, unsigned int limit, unsigned int * start, unsigned int * end, unsigned int color) { + + // Number of 32-bit integers the register can hold. + int pack = 4; + + // Track number of matching searches. + unsigned int count = 0; + + // Create a vector of four copies of color. + __m128i vcolor = _mm_set1_epi32(color); + + loop: + // Loop over start pointer with a step of four unsigned integers. + while (start < end - 3) { + + // Load four unsigned integers from start into a vector. + __m128i vstart = _mm_loadu_si128((__m128i *) start); + + // Compare vstart and vcolor for equality. + __m128i vcmp = _mm_cmpeq_epi32(vstart, vcolor); + + // Create a mask from each byte (using the most significant bit) in vcmp. + int mask = _mm_movemask_epi8(vcmp); + + // If the mask is nonzero, there is at least one match. + if (mask != 0) + break; + + // Increment start by four unsigned integers. + start += 4; + } + + // Clean up any remaining elements. + while (start < end) { + if (pack > 0) { + if (*start == color) { + if (count < limit) + *(result + count) = start; + count++; + } + pack--; + } + else { + pack = 4; + goto loop; + } + start++; + } + + return count; +} \ No newline at end of file diff --git a/source/pixelsearchall2x.c b/source/pixelsearchall2x.c new file mode 100644 index 00000000..c245af5b --- /dev/null +++ b/source/pixelsearchall2x.c @@ -0,0 +1,73 @@ +#include + +#define _mm_cmpge_epu8(a, b) _mm_cmpeq_epi8(_mm_max_epu8(a, b), a) +#define _mm_cmple_epu8(a, b) _mm_cmpge_epu8(b, a) +#define _mm_cmpgt_epu8(a, b) _mm_xor_si128(_mm_cmple_epu8(a, b), _mm_set1_epi8(-1)) +#define _mm_cmplt_epu8(a, b) _mm_cmpgt_epu8(b, a) + +unsigned int pixelsearchall2(unsigned int ** result, unsigned int limit, unsigned int * start, unsigned int * end, unsigned char rh, unsigned char rl, unsigned char gh, unsigned char gl, unsigned char bh, unsigned char bl) { + + // Number of 32-bit integers the register can hold. + int pack = 4; + + // Track number of matching searches. + unsigned int count = 0; + + // Reconstruct ARGB from individual color channels. + unsigned int h = (0xFF << 24 | rh << 16 | gh << 8 | bh << 0); + unsigned int l = (0x00 << 24 | rl << 16 | gl << 8 | bl << 0); + + // Create a vector of four copies. + __m128i vh = _mm_set1_epi32(h); + __m128i vl = _mm_set1_epi32(l); + __m128i vmask = _mm_set1_epi32(0xFFFFFFFF); + + loop: + // Loop over start pointer with a step of four unsigned integers. + while (start < end - 3) { + + // Load four unsigned integers from start into a vector. + __m128i vstart = _mm_loadu_si128((__m128i *) start); + + // Compare vstart <= vh and vstart >= vl. Note these are macros. + __m128i v2 = _mm_cmple_epu8(vstart, vh); + __m128i v3 = _mm_cmpge_epu8(vstart, vl); + __m128i v1234 = _mm_and_si128(v2, v3); + + // Compare equality to four unsigned integers. + __m128i vcmp = _mm_cmpeq_epi32(v1234, vmask); + + // Create a mask from each byte (using the most significant bit) in vcmp. + int mask = _mm_movemask_epi8(vcmp); + + // If the mask is nonzero, there is at least one match. + if (mask != 0) + break; + + start += 4; + } + + exit: + // Clean up any remaining elements. + unsigned char r, g, b; + while (start < end) { + if (pack > 0) { + r = *((unsigned char *) start + 2); + g = *((unsigned char *) start + 1); + b = *((unsigned char *) start + 0); + if (rh >= r && r >= rl && gh >= g && g >= gl && bh >= b && b >= bl) { + if (count < limit) + *(result + count) = start; + count++; + } + pack--; + } + else { + pack = 4; + goto loop; + } + start++; + } + + return count; +} \ No newline at end of file diff --git a/source/pixelsearchall3x.c b/source/pixelsearchall3x.c new file mode 100644 index 00000000..6a7c07c3 --- /dev/null +++ b/source/pixelsearchall3x.c @@ -0,0 +1,108 @@ +#include + +unsigned int pixelsearchall3(unsigned int ** result, unsigned int limit, unsigned int * start, unsigned int * end, unsigned int * colors, unsigned int length) { + + // Number of 32-bit integers the register can hold. + int pack = 4; + + // Track number of matching searches. + unsigned int count = 0; + + // Save the starting pointer position. + unsigned int * current = start; + + // Offset of pointer to stored colors. + int i = 0; + + // Number of colors left. + int n; + + // Determine how many matches to be run in sequence. + enter: + n = length - i; + if (n == 0) + return count; // Somehow goto exit creates a bigger binary in mcodeforgcc (not here though). + if (n == 1) + goto init_1; + if (n == 2) + goto init_2; + if (n > 2) + goto init_3; // Segue into next label. + + // Create vectors from pointer to stored colors. + init_3: + __m128i vcolor3 = _mm_set1_epi32(*(colors + i + 2)); + init_2: + __m128i vcolor2 = _mm_set1_epi32(*(colors + i + 1)); + init_1: + __m128i vcolor1 = _mm_set1_epi32(*(colors + i + 0)); + + // Restore starting pointer for each run. + start = current; + + loop: + // Somehow there are diminishing returns past running 3 checks at once. + if (n == 1) + goto check_1; + if (n == 2) + goto check_2; + if (n > 2) + goto check_3; // Segue into next label. + + check_3: + while (start < end - 3) { + __m128i vstart = _mm_loadu_si128((__m128i *) start); + if (_mm_movemask_epi8(_mm_cmpeq_epi32(vcolor1, vstart)) != 0) + goto exit; + if (_mm_movemask_epi8(_mm_cmpeq_epi32(vcolor2, vstart)) != 0) + goto exit; + if (_mm_movemask_epi8(_mm_cmpeq_epi32(vcolor3, vstart)) != 0) + goto exit; + start += 4; + } + i += 3; + goto enter; + + check_2: + while (start < end - 3) { + __m128i vstart = _mm_loadu_si128((__m128i *) start); + if (_mm_movemask_epi8(_mm_cmpeq_epi32(vcolor1, vstart)) != 0) + goto exit; + if (_mm_movemask_epi8(_mm_cmpeq_epi32(vcolor2, vstart)) != 0) + goto exit; + start += 4; + } + i += 2; + goto enter; + + check_1: + while (start < end - 3) { + __m128i vstart = _mm_loadu_si128((__m128i *) start); + if (_mm_movemask_epi8(_mm_cmpeq_epi32(vcolor1, vstart)) != 0) + goto exit; + start += 4; + } + i += 1; + goto enter; + + exit: + // Clean up any remaining elements. + while (start < end) { + if (pack > 0) { + for (int i = 0; i < length; i++) + if (*start == colors[i]) { + if (count < limit) + *(result + count) = start; + count++; + } + pack--; + } + else { + pack = 4; + goto loop; + } + start++; + } + + return count; +} \ No newline at end of file diff --git a/source/pixelsearchall4x.c b/source/pixelsearchall4x.c new file mode 100644 index 00000000..fa79a18c --- /dev/null +++ b/source/pixelsearchall4x.c @@ -0,0 +1,157 @@ +#include + +#define _mm_cmpge_epu8(a, b) _mm_cmpeq_epi8(_mm_max_epu8(a, b), a) +#define _mm_cmple_epu8(a, b) _mm_cmpge_epu8(b, a) +#define _mm_cmpgt_epu8(a, b) _mm_xor_si128(_mm_cmple_epu8(a, b), _mm_set1_epi8(-1)) +#define _mm_cmplt_epu8(a, b) _mm_cmpgt_epu8(b, a) + +unsigned int pixelsearchall4(unsigned int ** result, unsigned int limit, unsigned int * start, unsigned int * end, unsigned int * high, unsigned int * low, unsigned int length) { + + // Number of 32-bit integers the register can hold. + int pack = 4; + + // Track number of matching searches. + unsigned int count = 0; + + // Save the starting pointer position. + unsigned int * current = start; + + // Offset of pointer to stored colors. + int i = 0; + + // Number of colors left. + int n; + + // Comparison mask for unsigned integers. + __m128i vmask = _mm_set1_epi32(0xFFFFFFFF); + + // Determine how many matches to be run in sequence. + enter: + n = length - i; + if (n == 0) + return count; // Somehow goto exit creates a bigger binary in mcodeforgcc (not here though). + if (n == 1) + goto init_1; + if (n == 2) + goto init_2; + if (n > 2) + goto init_3; // Segue into next label. + + // Create vectors. + init_3: + __m128i vh3 = _mm_set1_epi32(*(high + i + 2)); + __m128i vl3 = _mm_set1_epi32(*(low + i + 2)); + init_2: + __m128i vh2 = _mm_set1_epi32(*(high + i + 1)); + __m128i vl2 = _mm_set1_epi32(*(low + i + 1)); + init_1: + __m128i vh1 = _mm_set1_epi32(*(high + i + 0)); + __m128i vl1 = _mm_set1_epi32(*(low + i + 0)); + + // Restore starting pointer for each run. + start = current; + + loop: + // Somehow there are diminishing returns past running 3 checks at once. + if (n == 1) + goto check_1; + if (n == 2) + goto check_2; + if (n > 2) + goto check_3; // Segue into next label. + + check_3: + while (start < end - 3) { + __m128i vstart = _mm_loadu_si128((__m128i *) start); + + if (_mm_movemask_epi8(_mm_cmpeq_epi32(vmask, + _mm_and_si128( + _mm_cmple_epu8(vstart, vh1), + _mm_cmpge_epu8(vstart, vl1)))) != 0) + goto exit; + if (_mm_movemask_epi8(_mm_cmpeq_epi32(vmask, + _mm_and_si128( + _mm_cmple_epu8(vstart, vh2), + _mm_cmpge_epu8(vstart, vl2)))) != 0) + goto exit; + if (_mm_movemask_epi8(_mm_cmpeq_epi32(vmask, + _mm_and_si128( + _mm_cmple_epu8(vstart, vh3), + _mm_cmpge_epu8(vstart, vl3)))) != 0) + goto exit; + + start += 4; + } + i += 3; + goto enter; + + check_2: + while (start < end - 3) { + __m128i vstart = _mm_loadu_si128((__m128i *) start); + + if (_mm_movemask_epi8(_mm_cmpeq_epi32(vmask, + _mm_and_si128( + _mm_cmple_epu8(vstart, vh1), + _mm_cmpge_epu8(vstart, vl1)))) != 0) + goto exit; + if (_mm_movemask_epi8(_mm_cmpeq_epi32(vmask, + _mm_and_si128( + _mm_cmple_epu8(vstart, vh2), + _mm_cmpge_epu8(vstart, vl2)))) != 0) + goto exit; + + start += 4; + } + i += 2; + goto enter; + + check_1: + while (start < end - 3) { + __m128i vstart = _mm_loadu_si128((__m128i *) start); + + if (_mm_movemask_epi8(_mm_cmpeq_epi32(vmask, + _mm_and_si128( + _mm_cmple_epu8(vstart, vh1), + _mm_cmpge_epu8(vstart, vl1)))) != 0) + goto exit; + + start += 4; + } + i += 1; + goto enter; + + exit: + // Clean up any remaining elements. + unsigned char r, g, b, rh, gh, bh, rl, gl, bl; + while (start < end) { + if (pack > 0) { + r = *((unsigned char *) start + 2); + g = *((unsigned char *) start + 1); + b = *((unsigned char *) start + 0); + + for (int i = 0; i < length; i++) { + + rh = *((unsigned char *) high + 4*i + 2); + gh = *((unsigned char *) high + 4*i + 1); + bh = *((unsigned char *) high + 4*i + 0); + rl = *((unsigned char *) low + 4*i + 2); + gl = *((unsigned char *) low + 4*i + 1); + bl = *((unsigned char *) low + 4*i + 0); + + if (rh >= r && r >= rl && gh >= g && g >= gl && bh >= b && b >= bl) { + if (count < limit) + *(result + count) = start; + count++; + } + } + pack--; + } + else { + pack = 4; + goto loop; + } + start++; + } + + return count; +} \ No newline at end of file From b84bff20a4484a687680020bd204fe369d5b4214 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 22 Sep 2023 23:49:22 -0400 Subject: [PATCH 460/492] Implement SSE2 acceleration for PixelSearchAll --- ImagePut (for v1).ahk | 67 +++++++++++++++++++++++++++++++------------ ImagePut.ahk | 67 +++++++++++++++++++++++++++++++------------ 2 files changed, 98 insertions(+), 36 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 5908b03f..9b87c6f0 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2619,28 +2619,59 @@ class ImagePut { ; ----------------------- Machine code generated with MCode4GCC using gcc 13.2.0 ----------------------- - ; C source code - https://godbolt.org/z/ahEsGeaxK + ; C source code - https://godbolt.org/z/ErbrhbWWE pixelsearchall1 := this.Base64Code((A_PtrSize == 4) - ? "VYnlVotNEItVDFOLRQhmD27RjVr0Zg9wygA52HMbDxAAZg92wWYP1/CF9nUMg8AQ6+g5CHQHg8AEOdBy9VteXcM=" - : "McBEi1QkKE05yHMYRTkQdQ050HMHQYnDTokE2f/ASYPABOvjww==") - - ; C source code - https://godbolt.org/z/hq55M66fP + ? "VTHSieVXZg9uVRiLRRBWU4tdFGYPcMoAjXP0OfBzDw8QAGYPdsFmD9fIhcl0BY1IEOsVjUgQicjr4TnIdPiLfRg5OHQJg8AEOdhy" + . "7usOO1UMcwaLfQiJBJdC6+lbidBeX13D" + : "VlMxwESLVCQ4ZkEPbtJmD3DKAEmNWfRJOdhNjVgQcyNBDxAAZg92wWYP1/CF9nUTTYnY6+JNOdh09kU5EHQLSYPABE05yHLt6w45" + . "0HMGicZMiQTx/8Dr51teww==") + + ; C source code - https://godbolt.org/z/PssjWcE5M pixelsearchall2 := this.Base64Code((A_PtrSize == 4) - ? "VTHAieVTi1UQi00UOcpzGItdGDkadQw7RQxzBotdCIkUg0CDwgTr5Ftdww==" - : "QVRVV1ZTMcBEilwkUIpcJFhAinQkYECKfCRoQIpsJHBEimQkeE05yHM8RYpQAkU403ItQTjacihFilABRDjWch9BOPpyGkWKEEQ4" - . "1XISRTjicg050HMHQYnCTokE0f/ASYPABOu/W15fXUFcww==") - - ; C source code - https://godbolt.org/z/9jT694Pdn + ? "VWYPduSJ5VdWU4Pk8IPsEItdGItNIItVKIpFHIhcJA8PttuLfRTB4xCIRCQOikUkiEwkDQ+2yY139IhUJAsPttLB4QgJ2ohEJAyK" + . "RSwJyg+2TSQPttiBygAAAP+IRCQKweEIZg9u6jHSCcsPtk0cZg9wzQDB4RAJy2YPbvNmD3DWADl1EHMri0UQDxAADxAYDxA4Zg/e" + . "wWYP3tpmD3TBZg903w9Uw2YPdsRmD9fIhcl0CItFEI1IEOsgi0UQjUgQiU0Q6705TRB09otFEIpYAjhcJA9zC4NFEAQ5fRBy5us0" + . "OlwkDnLvilgBOFwkDXLmOlwkDHLgihg4XCQLctg6XCQKctI7VQxzCYtFCItdEIkckELrwY1l9InQW15fXcM=" + : "QVdBVkFVQVRVV1ZTRItUJGiLhCSIAAAARIucJJAAAABAimwkcESJ10UPttJBicYPtsBBweIQRYnfRQ+220iJy4tMJHiJ1ouUJIAA" + . "AABECdBNjVH0QYnMD7bJQYnVD7bSweEIweIICchAD7bNRAnaweEQDQAAAP8JymYPbsAxwGYPbupmD3DIAGYPcMUAZg927U050EmN" + . "UBBzQEEPECAPKNEPKNxmD97UZg/e2GYPdNFmD3TcD1TTZg921WYP18qFyXUXSYnQ68lJOdB09kGKSAJAOM9zC0mDwARNOchy6esu" + . "QDjpcvBBikgBQTjMcudEOOly4kGKCEE4znLaRDj5ctU58HMGicFMiQTL/8Drx1teX11BXEFdQV5BX8M=") + + ; C source code - https://godbolt.org/z/zbPcWT1P3 pixelsearchall3 := this.Base64Code((A_PtrSize == 4) - ? "VYnlV4tFHItVEFZTi10YjTSDMcA7VRRzIonZOfF0F4s5OTp1DDtFDHMGi30IiRSHQIPBBOvlg8IE69lbXl9dww==" - : "UzHATItcJDBNOchzKkUx0kQ7VCQ4cxpDixyTQTkYdQw50HMGicNMiQTZ/8BJ/8Lr30mDwATr0VvD") - - ; C source code - https://godbolt.org/z/MhdaWq6fK + ? "VTHSMcmJ5VdWU4Pk8IPsEItdGItFHI0Eg4lEJASLRRSD6AyJRCQIi0UcKdCJRCQMD4QTAQAAg/gBdBuD+AJ0C2YPbmyTCGYPcN0A" + . "Zg9udJMEZg9w1gBmD248k4tFEGYPcM8Ag3wkDAF1C4t9FI139OmUAAAAg3wkDAJ0a4t8JAg5+HM6DxAADyjgZg924WYP1/SF9nUP" + . "DyjiZg924GYP1/SF9nQIjXAQiTQk63pmD3bDZg/X8IX2deyDwBDrvoPCA+lh////DxAADyjhZg924GYP1/SF9nXNZg92wmYP1/CF" + . "9nXBg8AQi3wkCDn4cteDwgLpMP///w8QAGYPdsFmD9f4hf91n4PAEDnwcupC6RT///+LPjk4dCKDxgSLfCQEOf5174PABDtFFHMd" + . "izwkOfgPhCz///+J3uvhO00McwaLfQiJBI9B69CNZfSJyFteX13D" + : "QVZBVUFUVVdWU0yLXCRgi2wkaEiJzonXMckx0k2NYfRBiepBKdIPhA4BAABIY8JBg/oBdB5Bg/oCdAxmQQ9ubIMIZg9w3QBmQQ9u" + . "bIMEZg9w1QBmQQ9uDINMicBmD3DJAEGD+gEPhI4AAABBg/oCdGhMOeBzOQ8QAA8o4GYPduFmD9fchdt1Dw8o4mYPduBmD9fchdt0" + . "BkyNaBDrfGYPdsNmD9fYhdt17kiDwBDrwoPCA+lp////DxAADyjhZg924GYP19yF23XOZg92wmYP19iF23XCSIPAEEw54HLZg8IC" + . "6Tr///8PEABmD3bBZg/X2IXbdaJIg8AQTDngcuj/wukb////RYs0m0Q5MHQdSP/DOety8EiDwARMOchzHEw56A+EOv///zHb6+Y5" + . "+XMHQYnOSokE9v/B69SJyFteX11BXEFdQV7D") + + ; C source code - https://godbolt.org/z/7oKb5Tnqd pixelsearchall4 := this.Base64Code((A_PtrSize == 4) - ? "VYnlV1ZTUYtVEDHJi30Yi3UcO1UUc1eKQgKIRfOKQgGIRfKKAohF8THAO0UgdDqKXfM4XIcCci46XIYCciiKXfI4XIcBch86XIYB" - . "chmKXfE4HIdyETochnIMO00McwaLXQiJFItBQOvBg8IE66RaichbXl9dww==" - : "QVVBVFVXVlNIi1wkWItEJGhMjSSDQYnTSYnKMdJNOchzWEGKcAJBingBSInYQYooSItMJGBMOeB0OkA4cAJyKkA6cQJyJEA4eAFy" - . "HkA6eQFyGEA4KHITQDopcg5EOdpzB0GJ1U+JBOr/wkiDwARIg8EE68FJg8AE66OJ0FteX11BXEFdww==") + ? "VTHAZg920onlVzH/VlOD5PCD7DCLdRyJRCQsi0UgKfiJRCQoD4RCAgAAg/gBdECD+AJ0IotFGGYPbmS4CGYPcOwADylsJBBmD25s" + . "vghmD3DdAA8pHCSLRRhmD25MvgRmD25kuARmD3DpAGYPcNwAi0UYZg9uJLiLRRBmD3DMAGYPbiS+Zg9w5ACDfCQoAXULi1UUg+oM" + . "6UYBAACDfCQoAnULi00UjVH06fUAAACLVRSD6gw50A+DiwAAAA8QAA8o+Q8o8GYP3vhmD970Zg90+WYPdPAPVPdmD3byZg/XzoXJ" + . "dSUPKPMPKPhmD97wZg/e/WYPdPNmD3T4D1T3Zg928mYP186FyXQMjUgQiUwkIOkBAQAADyg8JA8odCQQZg/e+GYP3vBmD3R0JBBm" + . "D3THD1TwZg928mYP186FyXXKg8AQ6W3///+DxwPpzf7//w8QAA8o+A8o8GYP3vxmD97xZg908WYPdPgPVPdmD3byZg/XzoXJdZIP" + . "KPgPKPNmD97wZg/e/WYPdPNmD3THD1TwZg928mYP186FyQ+Faf///4PAEDnQcqiDxwLpbf7//w8QMA8QAA8QOGYP3vRmD97BZg90" + . "wWYPdPcPVMZmD3YFAAAAAGYP18iFyQ+FKv///4PAEDnQcslH6TD+//+LVCQgOdAPhJL+//+KUAKIVCQnilABiFQkJooQiFQkJTHS" + . "O1UgdQqDwAQ7RRRy0etQi10YikwkJzhMkwJyQDpMlgJyOopMJCY4TJMBcjA6TJYBciqKTCQlOAyTciE6DJZyHItMJCw7TQxzCotN" + . "CItcJCyJBJmLTCQsQYlMJCxC66GLRCQsjWX0W15fXcM=" + : "QVdBVkFVQVRVV1ZTSIPsaA8pdCQQDyl8JCBEDylEJDBEDylMJEBEDylUJFBmD3bSTIuUJNAAAACLhCTgAAAASIu0JNgAAABJjQSC" + . "SImMJLAAAABJjXn0SIkEJImUJLgAAAAx0kyJhCTAAAAARTHAi5wk4AAAACnTD4RSAgAASGPCg/sBdDOD+wJ0F2ZBD258gghmD250" + . "hghmD3DvAGYPcP4AZkEPbmSCBGYPbnSGBGYPcNwAZg9w9gBmQQ9uJIJmD3DMAGYPbiSGSIuEJMAAAABmD3DkAGZFD3bJg/sBD4Rl" + . "AQAAg/sCD4QYAQAASDn4D4OiAAAADxAARA8oyUQPKMBmRA/eyGZED97EZkQPdMlmRA90wEUPVMFmRA92wmZBD9fIhcl1LkQPKMNE" + . "DyjIZkQP3sBmRA/ezmZED3TDZkQPdMhFD1TBZkQPdsJmQQ/XyIXJdA5IjUgQSIlMJAjpHgEAAEQPKMhEDyjFZkQP3sBmRA/ez2ZE" + . "D3TFZkEPdMFBD1TAZg92wmYP18iFyXXGSIPAEOlV////g8ID6c/+//8PEABEDyjIRA8owGZED97MZkQP3sFmRA90wWZED3TIRQ9U" + . "wWZED3bCZkEP18iFyXWERA8oyEQPKMNmRA/ewGZED97OZkQPdMNmQQ90wUEPVMBmD3bCZg/XyIXJD4VU////SIPAEEg5+HKWg8IC" + . "6V3+//9EDxAARQ8o0EEPKMBmRA/e1GYP3sFmD3TBZkUPdMJBD1TAZkEPdsFmD9fIhckPhRD///9Ig8AQSDn4csT/wuka/v//SItM" + . "JAhIOcgPhHP+//9AimgCRIpgAUmJ80yJ0USKKEyLNCRMOfF1C0iDwARMOchyz+tIQDhpAnI4QTprAnIyRDhhAXIsRTpjAXImRDgp" + . "ciFFOityHEQ7hCS4AAAAcw9Mi7QksAAAAEWJx0uJBP5B/8BIg8EESYPDBOukDyh0JBAPKHwkIESJwEQPKEQkMEQPKEwkQEQPKFQk" + . "UEiDxGhbXl9dQVxBXUFeQV/D") ; ------------------------------------------------------------------------------------------------------ diff --git a/ImagePut.ahk b/ImagePut.ahk index d1957e79..d7ed4b95 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2619,28 +2619,59 @@ class ImagePut { ; ----------------------- Machine code generated with MCode4GCC using gcc 13.2.0 ----------------------- - ; C source code - https://godbolt.org/z/ahEsGeaxK + ; C source code - https://godbolt.org/z/ErbrhbWWE pixelsearchall1 := this.Base64Code((A_PtrSize == 4) - ? "VYnlVotNEItVDFOLRQhmD27RjVr0Zg9wygA52HMbDxAAZg92wWYP1/CF9nUMg8AQ6+g5CHQHg8AEOdBy9VteXcM=" - : "McBEi1QkKE05yHMYRTkQdQ050HMHQYnDTokE2f/ASYPABOvjww==") - - ; C source code - https://godbolt.org/z/hq55M66fP + ? "VTHSieVXZg9uVRiLRRBWU4tdFGYPcMoAjXP0OfBzDw8QAGYPdsFmD9fIhcl0BY1IEOsVjUgQicjr4TnIdPiLfRg5OHQJg8AEOdhy" + . "7usOO1UMcwaLfQiJBJdC6+lbidBeX13D" + : "VlMxwESLVCQ4ZkEPbtJmD3DKAEmNWfRJOdhNjVgQcyNBDxAAZg92wWYP1/CF9nUTTYnY6+JNOdh09kU5EHQLSYPABE05yHLt6w45" + . "0HMGicZMiQTx/8Dr51teww==") + + ; C source code - https://godbolt.org/z/PssjWcE5M pixelsearchall2 := this.Base64Code((A_PtrSize == 4) - ? "VTHAieVTi1UQi00UOcpzGItdGDkadQw7RQxzBotdCIkUg0CDwgTr5Ftdww==" - : "QVRVV1ZTMcBEilwkUIpcJFhAinQkYECKfCRoQIpsJHBEimQkeE05yHM8RYpQAkU403ItQTjacihFilABRDjWch9BOPpyGkWKEEQ4" - . "1XISRTjicg050HMHQYnCTokE0f/ASYPABOu/W15fXUFcww==") - - ; C source code - https://godbolt.org/z/9jT694Pdn + ? "VWYPduSJ5VdWU4Pk8IPsEItdGItNIItVKIpFHIhcJA8PttuLfRTB4xCIRCQOikUkiEwkDQ+2yY139IhUJAsPttLB4QgJ2ohEJAyK" + . "RSwJyg+2TSQPttiBygAAAP+IRCQKweEIZg9u6jHSCcsPtk0cZg9wzQDB4RAJy2YPbvNmD3DWADl1EHMri0UQDxAADxAYDxA4Zg/e" + . "wWYP3tpmD3TBZg903w9Uw2YPdsRmD9fIhcl0CItFEI1IEOsgi0UQjUgQiU0Q6705TRB09otFEIpYAjhcJA9zC4NFEAQ5fRBy5us0" + . "OlwkDnLvilgBOFwkDXLmOlwkDHLgihg4XCQLctg6XCQKctI7VQxzCYtFCItdEIkckELrwY1l9InQW15fXcM=" + : "QVdBVkFVQVRVV1ZTRItUJGiLhCSIAAAARIucJJAAAABAimwkcESJ10UPttJBicYPtsBBweIQRYnfRQ+220iJy4tMJHiJ1ouUJIAA" + . "AABECdBNjVH0QYnMD7bJQYnVD7bSweEIweIICchAD7bNRAnaweEQDQAAAP8JymYPbsAxwGYPbupmD3DIAGYPcMUAZg927U050EmN" + . "UBBzQEEPECAPKNEPKNxmD97UZg/e2GYPdNFmD3TcD1TTZg921WYP18qFyXUXSYnQ68lJOdB09kGKSAJAOM9zC0mDwARNOchy6esu" + . "QDjpcvBBikgBQTjMcudEOOly4kGKCEE4znLaRDj5ctU58HMGicFMiQTL/8Drx1teX11BXEFdQV5BX8M=") + + ; C source code - https://godbolt.org/z/zbPcWT1P3 pixelsearchall3 := this.Base64Code((A_PtrSize == 4) - ? "VYnlV4tFHItVEFZTi10YjTSDMcA7VRRzIonZOfF0F4s5OTp1DDtFDHMGi30IiRSHQIPBBOvlg8IE69lbXl9dww==" - : "UzHATItcJDBNOchzKkUx0kQ7VCQ4cxpDixyTQTkYdQw50HMGicNMiQTZ/8BJ/8Lr30mDwATr0VvD") - - ; C source code - https://godbolt.org/z/MhdaWq6fK + ? "VTHSMcmJ5VdWU4Pk8IPsEItdGItFHI0Eg4lEJASLRRSD6AyJRCQIi0UcKdCJRCQMD4QTAQAAg/gBdBuD+AJ0C2YPbmyTCGYPcN0A" + . "Zg9udJMEZg9w1gBmD248k4tFEGYPcM8Ag3wkDAF1C4t9FI139OmUAAAAg3wkDAJ0a4t8JAg5+HM6DxAADyjgZg924WYP1/SF9nUP" + . "DyjiZg924GYP1/SF9nQIjXAQiTQk63pmD3bDZg/X8IX2deyDwBDrvoPCA+lh////DxAADyjhZg924GYP1/SF9nXNZg92wmYP1/CF" + . "9nXBg8AQi3wkCDn4cteDwgLpMP///w8QAGYPdsFmD9f4hf91n4PAEDnwcupC6RT///+LPjk4dCKDxgSLfCQEOf5174PABDtFFHMd" + . "izwkOfgPhCz///+J3uvhO00McwaLfQiJBI9B69CNZfSJyFteX13D" + : "QVZBVUFUVVdWU0yLXCRgi2wkaEiJzonXMckx0k2NYfRBiepBKdIPhA4BAABIY8JBg/oBdB5Bg/oCdAxmQQ9ubIMIZg9w3QBmQQ9u" + . "bIMEZg9w1QBmQQ9uDINMicBmD3DJAEGD+gEPhI4AAABBg/oCdGhMOeBzOQ8QAA8o4GYPduFmD9fchdt1Dw8o4mYPduBmD9fchdt0" + . "BkyNaBDrfGYPdsNmD9fYhdt17kiDwBDrwoPCA+lp////DxAADyjhZg924GYP19yF23XOZg92wmYP19iF23XCSIPAEEw54HLZg8IC" + . "6Tr///8PEABmD3bBZg/X2IXbdaJIg8AQTDngcuj/wukb////RYs0m0Q5MHQdSP/DOety8EiDwARMOchzHEw56A+EOv///zHb6+Y5" + . "+XMHQYnOSokE9v/B69SJyFteX11BXEFdQV7D") + + ; C source code - https://godbolt.org/z/7oKb5Tnqd pixelsearchall4 := this.Base64Code((A_PtrSize == 4) - ? "VYnlV1ZTUYtVEDHJi30Yi3UcO1UUc1eKQgKIRfOKQgGIRfKKAohF8THAO0UgdDqKXfM4XIcCci46XIYCciiKXfI4XIcBch86XIYB" - . "chmKXfE4HIdyETochnIMO00McwaLXQiJFItBQOvBg8IE66RaichbXl9dww==" - : "QVVBVFVXVlNIi1wkWItEJGhMjSSDQYnTSYnKMdJNOchzWEGKcAJBingBSInYQYooSItMJGBMOeB0OkA4cAJyKkA6cQJyJEA4eAFy" - . "HkA6eQFyGEA4KHITQDopcg5EOdpzB0GJ1U+JBOr/wkiDwARIg8EE68FJg8AE66OJ0FteX11BXEFdww==") + ? "VTHAZg920onlVzH/VlOD5PCD7DCLdRyJRCQsi0UgKfiJRCQoD4RCAgAAg/gBdECD+AJ0IotFGGYPbmS4CGYPcOwADylsJBBmD25s" + . "vghmD3DdAA8pHCSLRRhmD25MvgRmD25kuARmD3DpAGYPcNwAi0UYZg9uJLiLRRBmD3DMAGYPbiS+Zg9w5ACDfCQoAXULi1UUg+oM" + . "6UYBAACDfCQoAnULi00UjVH06fUAAACLVRSD6gw50A+DiwAAAA8QAA8o+Q8o8GYP3vhmD970Zg90+WYPdPAPVPdmD3byZg/XzoXJ" + . "dSUPKPMPKPhmD97wZg/e/WYPdPNmD3T4D1T3Zg928mYP186FyXQMjUgQiUwkIOkBAQAADyg8JA8odCQQZg/e+GYP3vBmD3R0JBBm" + . "D3THD1TwZg928mYP186FyXXKg8AQ6W3///+DxwPpzf7//w8QAA8o+A8o8GYP3vxmD97xZg908WYPdPgPVPdmD3byZg/XzoXJdZIP" + . "KPgPKPNmD97wZg/e/WYPdPNmD3THD1TwZg928mYP186FyQ+Faf///4PAEDnQcqiDxwLpbf7//w8QMA8QAA8QOGYP3vRmD97BZg90" + . "wWYPdPcPVMZmD3YFAAAAAGYP18iFyQ+FKv///4PAEDnQcslH6TD+//+LVCQgOdAPhJL+//+KUAKIVCQnilABiFQkJooQiFQkJTHS" + . "O1UgdQqDwAQ7RRRy0etQi10YikwkJzhMkwJyQDpMlgJyOopMJCY4TJMBcjA6TJYBciqKTCQlOAyTciE6DJZyHItMJCw7TQxzCotN" + . "CItcJCyJBJmLTCQsQYlMJCxC66GLRCQsjWX0W15fXcM=" + : "QVdBVkFVQVRVV1ZTSIPsaA8pdCQQDyl8JCBEDylEJDBEDylMJEBEDylUJFBmD3bSTIuUJNAAAACLhCTgAAAASIu0JNgAAABJjQSC" + . "SImMJLAAAABJjXn0SIkEJImUJLgAAAAx0kyJhCTAAAAARTHAi5wk4AAAACnTD4RSAgAASGPCg/sBdDOD+wJ0F2ZBD258gghmD250" + . "hghmD3DvAGYPcP4AZkEPbmSCBGYPbnSGBGYPcNwAZg9w9gBmQQ9uJIJmD3DMAGYPbiSGSIuEJMAAAABmD3DkAGZFD3bJg/sBD4Rl" + . "AQAAg/sCD4QYAQAASDn4D4OiAAAADxAARA8oyUQPKMBmRA/eyGZED97EZkQPdMlmRA90wEUPVMFmRA92wmZBD9fIhcl1LkQPKMNE" + . "DyjIZkQP3sBmRA/ezmZED3TDZkQPdMhFD1TBZkQPdsJmQQ/XyIXJdA5IjUgQSIlMJAjpHgEAAEQPKMhEDyjFZkQP3sBmRA/ez2ZE" + . "D3TFZkEPdMFBD1TAZg92wmYP18iFyXXGSIPAEOlV////g8ID6c/+//8PEABEDyjIRA8owGZED97MZkQP3sFmRA90wWZED3TIRQ9U" + . "wWZED3bCZkEP18iFyXWERA8oyEQPKMNmRA/ewGZED97OZkQPdMNmQQ90wUEPVMBmD3bCZg/XyIXJD4VU////SIPAEEg5+HKWg8IC" + . "6V3+//9EDxAARQ8o0EEPKMBmRA/e1GYP3sFmD3TBZkUPdMJBD1TAZkEPdsFmD9fIhckPhRD///9Ig8AQSDn4csT/wuka/v//SItM" + . "JAhIOcgPhHP+//9AimgCRIpgAUmJ80yJ0USKKEyLNCRMOfF1C0iDwARMOchyz+tIQDhpAnI4QTprAnIyRDhhAXIsRTpjAXImRDgp" + . "ciFFOityHEQ7hCS4AAAAcw9Mi7QksAAAAEWJx0uJBP5B/8BIg8EESYPDBOukDyh0JBAPKHwkIESJwEQPKEQkMEQPKEwkQEQPKFQk" + . "UEiDxGhbXl9dQVxBXUFeQV/D") ; ------------------------------------------------------------------------------------------------------ From da471e8d5cd42b1bdc9effdcd673b4c0aabb0ea7 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 23 Sep 2023 16:45:25 -0400 Subject: [PATCH 461/492] C source files Fix pixel inflation (double + triple counting etc.) --- source/__Note__.txt | 2 +- source/pixelsearch1x.c | 4 +-- source/pixelsearch1y.c | 6 ++-- source/pixelsearch2x.c | 11 +++--- source/pixelsearch3x.c | 49 +++++++++++++++----------- source/pixelsearch4x.c | 72 +++++++++++++++++++++---------------- source/pixelsearchall1x.c | 6 ++-- source/pixelsearchall2x.c | 9 ++--- source/pixelsearchall3x.c | 47 +++++++++++++++---------- source/pixelsearchall4x.c | 74 +++++++++++++++++++++++---------------- 10 files changed, 162 insertions(+), 118 deletions(-) diff --git a/source/__Note__.txt b/source/__Note__.txt index 78ec7c32..53351ad0 100644 --- a/source/__Note__.txt +++ b/source/__Note__.txt @@ -1,3 +1,3 @@ Use this at the top of your code to get the x64 calling convention -__attribute__((ms_abi)) \ No newline at end of file +__attribute__((ms_abi)) // Tells GCC we want to compile for Windows. \ No newline at end of file diff --git a/source/pixelsearch1x.c b/source/pixelsearch1x.c index 141bcc7e..c1c3f377 100644 --- a/source/pixelsearch1x.c +++ b/source/pixelsearch1x.c @@ -1,8 +1,8 @@ #include -unsigned int * pixelsearch1(unsigned int * start, unsigned int * end, unsigned int color) { +unsigned int * pixelsearch1x(unsigned int * start, unsigned int * end, unsigned int color) { - // Create a vector of four copies of color. + // Create a vector of four copies of the target color. __m128i vcolor = _mm_set1_epi32(color); // Loop over start pointer with a step of four unsigned integers. diff --git a/source/pixelsearch1y.c b/source/pixelsearch1y.c index 236ea8f0..2b0ee078 100644 --- a/source/pixelsearch1y.c +++ b/source/pixelsearch1y.c @@ -1,8 +1,8 @@ #include -unsigned int * pixelsearch1(unsigned int * start, unsigned int * end, unsigned int color) { - - // Create a vector of eight copies of color. +unsigned int * pixelsearch1y(unsigned int * start, unsigned int * end, unsigned int color) { + + // Create a vector of eight copies of the target color. __m256i vcolor = _mm256_set1_epi32(color); // Loop over start pointer with a step of eight unsigned integers. diff --git a/source/pixelsearch2x.c b/source/pixelsearch2x.c index 8af498d2..d068d4e2 100644 --- a/source/pixelsearch2x.c +++ b/source/pixelsearch2x.c @@ -5,13 +5,13 @@ #define _mm_cmpgt_epu8(a, b) _mm_xor_si128(_mm_cmple_epu8(a, b), _mm_set1_epi8(-1)) #define _mm_cmplt_epu8(a, b) _mm_cmpgt_epu8(b, a) -unsigned int * pixelsearch2(unsigned int * start, unsigned int * end, unsigned char rh, unsigned char rl, unsigned char gh, unsigned char gl, unsigned char bh, unsigned char bl) { +unsigned int * pixelsearch2x(unsigned int * start, unsigned int * end, unsigned char rh, unsigned char rl, unsigned char gh, unsigned char gl, unsigned char bh, unsigned char bl) { // Reconstruct ARGB from individual color channels. unsigned int h = (0xFF << 24 | rh << 16 | gh << 8 | bh << 0); unsigned int l = (0x00 << 24 | rl << 16 | gl << 8 | bl << 0); - // Create a vector of four copies. + // Create a vector of four copies of the target color. __m128i vh = _mm_set1_epi32(h); __m128i vl = _mm_set1_epi32(l); __m128i vmask = _mm_set1_epi32(0xFFFFFFFF); @@ -26,7 +26,7 @@ unsigned int * pixelsearch2(unsigned int * start, unsigned int * end, unsigned c __m128i v2 = _mm_cmple_epu8(vstart, vh); __m128i v3 = _mm_cmpge_epu8(vstart, vl); __m128i v1234 = _mm_and_si128(v2, v3); - + // Compare equality to four unsigned integers. __m128i vcmp = _mm_cmpeq_epi32(v1234, vmask); @@ -36,10 +36,11 @@ unsigned int * pixelsearch2(unsigned int * start, unsigned int * end, unsigned c // If the mask is nonzero, there is at least one match. if (mask != 0) break; - + + // Increment start by four unsigned integers. start += 4; } - + // Clean up any remaining elements. unsigned char r, g, b; while (start < end) { diff --git a/source/pixelsearch3x.c b/source/pixelsearch3x.c index cc5aefda..cc2249dc 100644 --- a/source/pixelsearch3x.c +++ b/source/pixelsearch3x.c @@ -1,6 +1,6 @@ #include -unsigned int * pixelsearch3(unsigned int * start, unsigned int * end, unsigned int * colors, unsigned int length) { +unsigned int * pixelsearch3x(unsigned int * start, unsigned int * end, unsigned int * colors, unsigned int length) { // Save the starting pointer position. unsigned int * current = start; @@ -11,19 +11,28 @@ unsigned int * pixelsearch3(unsigned int * start, unsigned int * end, unsigned i // Number of colors left. int n; + // Somehow there are diminishing returns past running 3 checks at once. + int check; + // Determine how many matches to be run in sequence. enter: n = length - i; if (n == 0) - return end; // Somehow goto exit creates a bigger binary in mcodeforgcc (not here though). - if (n == 1) + return end; // Somehow goto exit creates a bigger binary in mcodeforgcc. + if (n == 1) { + check = 1; goto init_1; - if (n == 2) + } + if (n == 2) { + check = 2; goto init_2; - if (n > 2) + } + if (n > 2) { + check = 3; goto init_3; // Segue into next label. + } - // Create vectors from pointer to stored colors. + // Create a vector of four copies of the target color. init_3: __m128i vcolor3 = _mm_set1_epi32(*(colors + i + 2)); init_2: @@ -34,22 +43,21 @@ unsigned int * pixelsearch3(unsigned int * start, unsigned int * end, unsigned i // Restore starting pointer for each run. start = current; - // Somehow there are diminishing returns past running 3 checks at once. + // Loop over start pointer with a step of four unsigned integers. if (n == 1) goto check_1; if (n == 2) goto check_2; if (n > 2) - goto check_3; // Segue into next label. + goto check_3; // Segue into next label. check_3: while (start < end - 3) { __m128i vstart = _mm_loadu_si128((__m128i *) start); - if (_mm_movemask_epi8(_mm_cmpeq_epi32(vcolor1, vstart)) != 0) - goto exit; - if (_mm_movemask_epi8(_mm_cmpeq_epi32(vcolor2, vstart)) != 0) - goto exit; - if (_mm_movemask_epi8(_mm_cmpeq_epi32(vcolor3, vstart)) != 0) + int mask1 = _mm_movemask_epi8(_mm_cmpeq_epi32(vcolor1, vstart)); + int mask2 = _mm_movemask_epi8(_mm_cmpeq_epi32(vcolor2, vstart)); + int mask3 = _mm_movemask_epi8(_mm_cmpeq_epi32(vcolor3, vstart)); + if (mask1 != 0 || mask2 != 0 || mask3 != 0) goto exit; start += 4; } @@ -59,9 +67,9 @@ unsigned int * pixelsearch3(unsigned int * start, unsigned int * end, unsigned i check_2: while (start < end - 3) { __m128i vstart = _mm_loadu_si128((__m128i *) start); - if (_mm_movemask_epi8(_mm_cmpeq_epi32(vcolor1, vstart)) != 0) - goto exit; - if (_mm_movemask_epi8(_mm_cmpeq_epi32(vcolor2, vstart)) != 0) + int mask1 = _mm_movemask_epi8(_mm_cmpeq_epi32(vcolor1, vstart)); + int mask2 = _mm_movemask_epi8(_mm_cmpeq_epi32(vcolor2, vstart)); + if (mask1 != 0 || mask2 != 0) goto exit; start += 4; } @@ -71,18 +79,19 @@ unsigned int * pixelsearch3(unsigned int * start, unsigned int * end, unsigned i check_1: while (start < end - 3) { __m128i vstart = _mm_loadu_si128((__m128i *) start); - if (_mm_movemask_epi8(_mm_cmpeq_epi32(vcolor1, vstart)) != 0) + int mask1 = _mm_movemask_epi8(_mm_cmpeq_epi32(vcolor1, vstart)); + if (mask1 != 0) goto exit; start += 4; } i += 1; goto enter; - exit: // Clean up any remaining elements. + exit: while (start < end) { - for (int i = 0; i < length; i++) - if (*start == colors[i]) + for (int j = 0; j < check; j++) + if (*start == colors[i + j]) return start; start++; } diff --git a/source/pixelsearch4x.c b/source/pixelsearch4x.c index 03339500..e4319fb8 100644 --- a/source/pixelsearch4x.c +++ b/source/pixelsearch4x.c @@ -5,7 +5,7 @@ #define _mm_cmpgt_epu8(a, b) _mm_xor_si128(_mm_cmple_epu8(a, b), _mm_set1_epi8(-1)) #define _mm_cmplt_epu8(a, b) _mm_cmpgt_epu8(b, a) -unsigned int * pixelsearch4(unsigned int * start, unsigned int * end, unsigned int * high, unsigned int * low, unsigned int length) { +unsigned int * pixelsearch4x(unsigned int * start, unsigned int * end, unsigned int * high, unsigned int * low, unsigned int length) { // Save the starting pointer position. unsigned int * current = start; @@ -16,6 +16,9 @@ unsigned int * pixelsearch4(unsigned int * start, unsigned int * end, unsigned i // Number of colors left. int n; + // Somehow there are diminishing returns past running 3 checks at once. + int check; + // Comparison mask for unsigned integers. __m128i vmask = _mm_set1_epi32(0xFFFFFFFF); @@ -23,15 +26,21 @@ unsigned int * pixelsearch4(unsigned int * start, unsigned int * end, unsigned i enter: n = length - i; if (n == 0) - return end; // Somehow goto exit creates a bigger binary in mcodeforgcc (not here though). - if (n == 1) + return end; // Somehow goto exit creates a bigger binary in mcodeforgcc. + if (n == 1) { + check = 1; goto init_1; - if (n == 2) + } + if (n == 2) { + check = 2; goto init_2; - if (n > 2) + } + if (n > 2) { + check = 3; goto init_3; // Segue into next label. + } - // Create vectors. + // Create a vector of four copies of the target color. init_3: __m128i vh3 = _mm_set1_epi32(*(high + i + 2)); __m128i vl3 = _mm_set1_epi32(*(low + i + 2)); @@ -45,7 +54,7 @@ unsigned int * pixelsearch4(unsigned int * start, unsigned int * end, unsigned i // Restore starting pointer for each run. start = current; - // Somehow there are diminishing returns past running 3 checks at once. + // Loop over start pointer with a step of four unsigned integers. if (n == 1) goto check_1; if (n == 2) @@ -57,20 +66,20 @@ unsigned int * pixelsearch4(unsigned int * start, unsigned int * end, unsigned i while (start < end - 3) { __m128i vstart = _mm_loadu_si128((__m128i *) start); - if (_mm_movemask_epi8(_mm_cmpeq_epi32(vmask, + int mask1 = _mm_movemask_epi8(_mm_cmpeq_epi32(vmask, _mm_and_si128( _mm_cmple_epu8(vstart, vh1), - _mm_cmpge_epu8(vstart, vl1)))) != 0) - goto exit; - if (_mm_movemask_epi8(_mm_cmpeq_epi32(vmask, + _mm_cmpge_epu8(vstart, vl1)))); + int mask2 = _mm_movemask_epi8(_mm_cmpeq_epi32(vmask, _mm_and_si128( _mm_cmple_epu8(vstart, vh2), - _mm_cmpge_epu8(vstart, vl2)))) != 0) - goto exit; - if (_mm_movemask_epi8(_mm_cmpeq_epi32(vmask, + _mm_cmpge_epu8(vstart, vl2)))); + int mask3 = _mm_movemask_epi8(_mm_cmpeq_epi32(vmask, _mm_and_si128( _mm_cmple_epu8(vstart, vh3), - _mm_cmpge_epu8(vstart, vl3)))) != 0) + _mm_cmpge_epu8(vstart, vl3)))); + + if (mask1 != 0 || mask2 != 0 || mask3 != 0) goto exit; start += 4; @@ -82,15 +91,16 @@ unsigned int * pixelsearch4(unsigned int * start, unsigned int * end, unsigned i while (start < end - 3) { __m128i vstart = _mm_loadu_si128((__m128i *) start); - if (_mm_movemask_epi8(_mm_cmpeq_epi32(vmask, + int mask1 = _mm_movemask_epi8(_mm_cmpeq_epi32(vmask, _mm_and_si128( _mm_cmple_epu8(vstart, vh1), - _mm_cmpge_epu8(vstart, vl1)))) != 0) - goto exit; - if (_mm_movemask_epi8(_mm_cmpeq_epi32(vmask, + _mm_cmpge_epu8(vstart, vl1)))); + int mask2 = _mm_movemask_epi8(_mm_cmpeq_epi32(vmask, _mm_and_si128( _mm_cmple_epu8(vstart, vh2), - _mm_cmpge_epu8(vstart, vl2)))) != 0) + _mm_cmpge_epu8(vstart, vl2)))); + + if (mask1 != 0 || mask2 != 0) goto exit; start += 4; @@ -102,10 +112,12 @@ unsigned int * pixelsearch4(unsigned int * start, unsigned int * end, unsigned i while (start < end - 3) { __m128i vstart = _mm_loadu_si128((__m128i *) start); - if (_mm_movemask_epi8(_mm_cmpeq_epi32(vmask, + int mask1 = _mm_movemask_epi8(_mm_cmpeq_epi32(vmask, _mm_and_si128( _mm_cmple_epu8(vstart, vh1), - _mm_cmpge_epu8(vstart, vl1)))) != 0) + _mm_cmpge_epu8(vstart, vl1)))); + + if (mask1 != 0) goto exit; start += 4; @@ -113,8 +125,8 @@ unsigned int * pixelsearch4(unsigned int * start, unsigned int * end, unsigned i i += 1; goto enter; - exit: // Clean up any remaining elements. + exit: unsigned char r, g, b, rh, gh, bh, rl, gl, bl; while (start < end) { @@ -122,14 +134,14 @@ unsigned int * pixelsearch4(unsigned int * start, unsigned int * end, unsigned i g = *((unsigned char *) start + 1); b = *((unsigned char *) start + 0); - for (int i = 0; i < length; i++) { + for (int j = 0; j < check; j++) { - rh = *((unsigned char *) high + 4*i + 2); - gh = *((unsigned char *) high + 4*i + 1); - bh = *((unsigned char *) high + 4*i + 0); - rl = *((unsigned char *) low + 4*i + 2); - gl = *((unsigned char *) low + 4*i + 1); - bl = *((unsigned char *) low + 4*i + 0); + rh = *((unsigned char *) high + 4*(i + j) + 2); + gh = *((unsigned char *) high + 4*(i + j) + 1); + bh = *((unsigned char *) high + 4*(i + j) + 0); + rl = *((unsigned char *) low + 4*(i + j) + 2); + gl = *((unsigned char *) low + 4*(i + j) + 1); + bl = *((unsigned char *) low + 4*(i + j) + 0); if (rh >= r && r >= rl && gh >= g && g >= gl && bh >= b && b >= bl) return start; diff --git a/source/pixelsearchall1x.c b/source/pixelsearchall1x.c index 95614592..57addb51 100644 --- a/source/pixelsearchall1x.c +++ b/source/pixelsearchall1x.c @@ -1,6 +1,6 @@ #include -unsigned int pixelsearchall1(unsigned int ** result, unsigned int limit, unsigned int * start, unsigned int * end, unsigned int color) { +unsigned int pixelsearchall1x(unsigned int ** result, unsigned int limit, unsigned int * start, unsigned int * end, unsigned int color) { // Number of 32-bit integers the register can hold. int pack = 4; @@ -8,11 +8,11 @@ unsigned int pixelsearchall1(unsigned int ** result, unsigned int limit, unsigne // Track number of matching searches. unsigned int count = 0; - // Create a vector of four copies of color. + // Create a vector of four copies of the target color. __m128i vcolor = _mm_set1_epi32(color); - loop: // Loop over start pointer with a step of four unsigned integers. + loop: while (start < end - 3) { // Load four unsigned integers from start into a vector. diff --git a/source/pixelsearchall2x.c b/source/pixelsearchall2x.c index c245af5b..ab1742c9 100644 --- a/source/pixelsearchall2x.c +++ b/source/pixelsearchall2x.c @@ -5,7 +5,7 @@ #define _mm_cmpgt_epu8(a, b) _mm_xor_si128(_mm_cmple_epu8(a, b), _mm_set1_epi8(-1)) #define _mm_cmplt_epu8(a, b) _mm_cmpgt_epu8(b, a) -unsigned int pixelsearchall2(unsigned int ** result, unsigned int limit, unsigned int * start, unsigned int * end, unsigned char rh, unsigned char rl, unsigned char gh, unsigned char gl, unsigned char bh, unsigned char bl) { +unsigned int pixelsearchall2x(unsigned int ** result, unsigned int limit, unsigned int * start, unsigned int * end, unsigned char rh, unsigned char rl, unsigned char gh, unsigned char gl, unsigned char bh, unsigned char bl) { // Number of 32-bit integers the register can hold. int pack = 4; @@ -17,13 +17,13 @@ unsigned int pixelsearchall2(unsigned int ** result, unsigned int limit, unsigne unsigned int h = (0xFF << 24 | rh << 16 | gh << 8 | bh << 0); unsigned int l = (0x00 << 24 | rl << 16 | gl << 8 | bl << 0); - // Create a vector of four copies. + // Create a vector of four copies of the target color. __m128i vh = _mm_set1_epi32(h); __m128i vl = _mm_set1_epi32(l); __m128i vmask = _mm_set1_epi32(0xFFFFFFFF); - loop: // Loop over start pointer with a step of four unsigned integers. + loop: while (start < end - 3) { // Load four unsigned integers from start into a vector. @@ -44,11 +44,12 @@ unsigned int pixelsearchall2(unsigned int ** result, unsigned int limit, unsigne if (mask != 0) break; + // Increment start by four unsigned integers. start += 4; } - exit: // Clean up any remaining elements. + exit: unsigned char r, g, b; while (start < end) { if (pack > 0) { diff --git a/source/pixelsearchall3x.c b/source/pixelsearchall3x.c index 6a7c07c3..acdef36b 100644 --- a/source/pixelsearchall3x.c +++ b/source/pixelsearchall3x.c @@ -1,6 +1,6 @@ #include -unsigned int pixelsearchall3(unsigned int ** result, unsigned int limit, unsigned int * start, unsigned int * end, unsigned int * colors, unsigned int length) { +unsigned int pixelsearchall3x(unsigned int ** result, unsigned int limit, unsigned int * start, unsigned int * end, unsigned int * colors, unsigned int length) { // Number of 32-bit integers the register can hold. int pack = 4; @@ -17,19 +17,28 @@ unsigned int pixelsearchall3(unsigned int ** result, unsigned int limit, unsigne // Number of colors left. int n; + // Somehow there are diminishing returns past running 3 checks at once. + int check; + // Determine how many matches to be run in sequence. enter: n = length - i; if (n == 0) - return count; // Somehow goto exit creates a bigger binary in mcodeforgcc (not here though). - if (n == 1) + return count; // Somehow goto exit creates a bigger binary in mcodeforgcc. + if (n == 1) { + check = 1; goto init_1; - if (n == 2) + } + if (n == 2) { + check = 2; goto init_2; - if (n > 2) + } + if (n > 2) { + check = 3; goto init_3; // Segue into next label. + } - // Create vectors from pointer to stored colors. + // Create a vector of four copies of the target color. init_3: __m128i vcolor3 = _mm_set1_epi32(*(colors + i + 2)); init_2: @@ -40,8 +49,8 @@ unsigned int pixelsearchall3(unsigned int ** result, unsigned int limit, unsigne // Restore starting pointer for each run. start = current; + // Loop over start pointer with a step of four unsigned integers. loop: - // Somehow there are diminishing returns past running 3 checks at once. if (n == 1) goto check_1; if (n == 2) @@ -52,11 +61,10 @@ unsigned int pixelsearchall3(unsigned int ** result, unsigned int limit, unsigne check_3: while (start < end - 3) { __m128i vstart = _mm_loadu_si128((__m128i *) start); - if (_mm_movemask_epi8(_mm_cmpeq_epi32(vcolor1, vstart)) != 0) - goto exit; - if (_mm_movemask_epi8(_mm_cmpeq_epi32(vcolor2, vstart)) != 0) - goto exit; - if (_mm_movemask_epi8(_mm_cmpeq_epi32(vcolor3, vstart)) != 0) + int mask1 = _mm_movemask_epi8(_mm_cmpeq_epi32(vcolor1, vstart)); + int mask2 = _mm_movemask_epi8(_mm_cmpeq_epi32(vcolor2, vstart)); + int mask3 = _mm_movemask_epi8(_mm_cmpeq_epi32(vcolor3, vstart)); + if (mask1 != 0 || mask2 != 0 || mask3 != 0) goto exit; start += 4; } @@ -66,9 +74,9 @@ unsigned int pixelsearchall3(unsigned int ** result, unsigned int limit, unsigne check_2: while (start < end - 3) { __m128i vstart = _mm_loadu_si128((__m128i *) start); - if (_mm_movemask_epi8(_mm_cmpeq_epi32(vcolor1, vstart)) != 0) - goto exit; - if (_mm_movemask_epi8(_mm_cmpeq_epi32(vcolor2, vstart)) != 0) + int mask1 = _mm_movemask_epi8(_mm_cmpeq_epi32(vcolor1, vstart)); + int mask2 = _mm_movemask_epi8(_mm_cmpeq_epi32(vcolor2, vstart)); + if (mask1 != 0 || mask2 != 0) goto exit; start += 4; } @@ -78,19 +86,20 @@ unsigned int pixelsearchall3(unsigned int ** result, unsigned int limit, unsigne check_1: while (start < end - 3) { __m128i vstart = _mm_loadu_si128((__m128i *) start); - if (_mm_movemask_epi8(_mm_cmpeq_epi32(vcolor1, vstart)) != 0) + int mask1 = _mm_movemask_epi8(_mm_cmpeq_epi32(vcolor1, vstart)); + if (mask1 != 0) goto exit; start += 4; } i += 1; goto enter; - exit: // Clean up any remaining elements. + exit: while (start < end) { if (pack > 0) { - for (int i = 0; i < length; i++) - if (*start == colors[i]) { + for (int j = 0; j < check; j++) + if (*start == colors[i + j]) { if (count < limit) *(result + count) = start; count++; diff --git a/source/pixelsearchall4x.c b/source/pixelsearchall4x.c index fa79a18c..db28bc48 100644 --- a/source/pixelsearchall4x.c +++ b/source/pixelsearchall4x.c @@ -5,7 +5,7 @@ #define _mm_cmpgt_epu8(a, b) _mm_xor_si128(_mm_cmple_epu8(a, b), _mm_set1_epi8(-1)) #define _mm_cmplt_epu8(a, b) _mm_cmpgt_epu8(b, a) -unsigned int pixelsearchall4(unsigned int ** result, unsigned int limit, unsigned int * start, unsigned int * end, unsigned int * high, unsigned int * low, unsigned int length) { +unsigned int pixelsearchall4x(unsigned int ** result, unsigned int limit, unsigned int * start, unsigned int * end, unsigned int * high, unsigned int * low, unsigned int length) { // Number of 32-bit integers the register can hold. int pack = 4; @@ -22,6 +22,9 @@ unsigned int pixelsearchall4(unsigned int ** result, unsigned int limit, unsigne // Number of colors left. int n; + // Somehow there are diminishing returns past running 3 checks at once. + int check; + // Comparison mask for unsigned integers. __m128i vmask = _mm_set1_epi32(0xFFFFFFFF); @@ -29,15 +32,21 @@ unsigned int pixelsearchall4(unsigned int ** result, unsigned int limit, unsigne enter: n = length - i; if (n == 0) - return count; // Somehow goto exit creates a bigger binary in mcodeforgcc (not here though). - if (n == 1) + return count; // Somehow goto exit creates a bigger binary in mcodeforgcc. + if (n == 1) { + check = 1; goto init_1; - if (n == 2) + } + if (n == 2) { + check = 2; goto init_2; - if (n > 2) + } + if (n > 2) { + check = 3; goto init_3; // Segue into next label. + } - // Create vectors. + // Create a vector of four copies of the target color. init_3: __m128i vh3 = _mm_set1_epi32(*(high + i + 2)); __m128i vl3 = _mm_set1_epi32(*(low + i + 2)); @@ -51,33 +60,33 @@ unsigned int pixelsearchall4(unsigned int ** result, unsigned int limit, unsigne // Restore starting pointer for each run. start = current; + // Loop over start pointer with a step of four unsigned integers. loop: - // Somehow there are diminishing returns past running 3 checks at once. if (n == 1) goto check_1; if (n == 2) goto check_2; if (n > 2) - goto check_3; // Segue into next label. + goto check_3; // Segue into next label. check_3: while (start < end - 3) { __m128i vstart = _mm_loadu_si128((__m128i *) start); - if (_mm_movemask_epi8(_mm_cmpeq_epi32(vmask, + int mask1 = _mm_movemask_epi8(_mm_cmpeq_epi32(vmask, _mm_and_si128( _mm_cmple_epu8(vstart, vh1), - _mm_cmpge_epu8(vstart, vl1)))) != 0) - goto exit; - if (_mm_movemask_epi8(_mm_cmpeq_epi32(vmask, + _mm_cmpge_epu8(vstart, vl1)))); + int mask2 = _mm_movemask_epi8(_mm_cmpeq_epi32(vmask, _mm_and_si128( _mm_cmple_epu8(vstart, vh2), - _mm_cmpge_epu8(vstart, vl2)))) != 0) - goto exit; - if (_mm_movemask_epi8(_mm_cmpeq_epi32(vmask, + _mm_cmpge_epu8(vstart, vl2)))); + int mask3 = _mm_movemask_epi8(_mm_cmpeq_epi32(vmask, _mm_and_si128( _mm_cmple_epu8(vstart, vh3), - _mm_cmpge_epu8(vstart, vl3)))) != 0) + _mm_cmpge_epu8(vstart, vl3)))); + + if (mask1 != 0 || mask2 != 0 || mask3 != 0) goto exit; start += 4; @@ -89,15 +98,16 @@ unsigned int pixelsearchall4(unsigned int ** result, unsigned int limit, unsigne while (start < end - 3) { __m128i vstart = _mm_loadu_si128((__m128i *) start); - if (_mm_movemask_epi8(_mm_cmpeq_epi32(vmask, + int mask1 = _mm_movemask_epi8(_mm_cmpeq_epi32(vmask, _mm_and_si128( _mm_cmple_epu8(vstart, vh1), - _mm_cmpge_epu8(vstart, vl1)))) != 0) - goto exit; - if (_mm_movemask_epi8(_mm_cmpeq_epi32(vmask, + _mm_cmpge_epu8(vstart, vl1)))); + int mask2 = _mm_movemask_epi8(_mm_cmpeq_epi32(vmask, _mm_and_si128( _mm_cmple_epu8(vstart, vh2), - _mm_cmpge_epu8(vstart, vl2)))) != 0) + _mm_cmpge_epu8(vstart, vl2)))); + + if (mask1 != 0 || mask2 != 0) goto exit; start += 4; @@ -109,10 +119,12 @@ unsigned int pixelsearchall4(unsigned int ** result, unsigned int limit, unsigne while (start < end - 3) { __m128i vstart = _mm_loadu_si128((__m128i *) start); - if (_mm_movemask_epi8(_mm_cmpeq_epi32(vmask, + int mask1 = _mm_movemask_epi8(_mm_cmpeq_epi32(vmask, _mm_and_si128( _mm_cmple_epu8(vstart, vh1), - _mm_cmpge_epu8(vstart, vl1)))) != 0) + _mm_cmpge_epu8(vstart, vl1)))); + + if (mask1 != 0) goto exit; start += 4; @@ -120,8 +132,8 @@ unsigned int pixelsearchall4(unsigned int ** result, unsigned int limit, unsigne i += 1; goto enter; - exit: // Clean up any remaining elements. + exit: unsigned char r, g, b, rh, gh, bh, rl, gl, bl; while (start < end) { if (pack > 0) { @@ -129,14 +141,14 @@ unsigned int pixelsearchall4(unsigned int ** result, unsigned int limit, unsigne g = *((unsigned char *) start + 1); b = *((unsigned char *) start + 0); - for (int i = 0; i < length; i++) { + for (int j = 0; j < check; j++) { - rh = *((unsigned char *) high + 4*i + 2); - gh = *((unsigned char *) high + 4*i + 1); - bh = *((unsigned char *) high + 4*i + 0); - rl = *((unsigned char *) low + 4*i + 2); - gl = *((unsigned char *) low + 4*i + 1); - bl = *((unsigned char *) low + 4*i + 0); + rh = *((unsigned char *) high + 4*(i + j) + 2); + gh = *((unsigned char *) high + 4*(i + j) + 1); + bh = *((unsigned char *) high + 4*(i + j) + 0); + rl = *((unsigned char *) low + 4*(i + j) + 2); + gl = *((unsigned char *) low + 4*(i + j) + 1); + bl = *((unsigned char *) low + 4*(i + j) + 0); if (rh >= r && r >= rl && gh >= g && g >= gl && bh >= b && b >= bl) { if (count < limit) From 44d046d4f5a90e6947fe99bdd3f29ab616e45bb0 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 23 Sep 2023 16:51:40 -0400 Subject: [PATCH 462/492] C source files --- source/pixelsearchall2x.c | 1 - 1 file changed, 1 deletion(-) diff --git a/source/pixelsearchall2x.c b/source/pixelsearchall2x.c index ab1742c9..4cef244c 100644 --- a/source/pixelsearchall2x.c +++ b/source/pixelsearchall2x.c @@ -49,7 +49,6 @@ unsigned int pixelsearchall2x(unsigned int ** result, unsigned int limit, unsign } // Clean up any remaining elements. - exit: unsigned char r, g, b; while (start < end) { if (pack > 0) { From 63f32cb219484dc2021350d8451b88faa46056e7 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 23 Sep 2023 17:45:55 -0400 Subject: [PATCH 463/492] Fix pixel inflation; Regenerate machine code and linkes --- ImagePut (for v1).ahk | 135 ++++++++++++++++++++++-------------------- ImagePut.ahk | 135 ++++++++++++++++++++++-------------------- 2 files changed, 140 insertions(+), 130 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 9b87c6f0..3b298904 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2414,12 +2414,12 @@ class ImagePut { ; ----------------------- Machine code generated with MCode4GCC using gcc 13.2.0 ----------------------- - ; C source code - https://godbolt.org/z/6jPnc6b5s + ; C source code - https://godbolt.org/z/zr71creqn pixelsearch1 := this.Base64Code((A_PtrSize == 4) ? "VYnlVotNEItVDFOLRQhmD27RjVr0Zg9wygA52HMbDxAAZg92wWYP1/CF9nUMg8AQ6+g5CHQHg8AEOdBy9VteXcM=" : "ZkEPbtBIichIjUr0Zg9wygBIOchzIA8QAGYPdsFmRA/XyEWFyXUPSIPAEOvkRDkAdAlIg8AESDnQcvLD") - ; C source code - https://godbolt.org/z/7fv3P6KTb + ; C source code - https://godbolt.org/z/65Yvsvs1G pixelsearch2 := this.Base64Code((A_PtrSize == 4) ? "VWYPduSJ5VdWU4Pk8IPsEIpFFItdEItNGItVHIt1DIt9IIhEJA6KRSSIXCQPD7bbiEwkDcHjEA+2yYhEJAsPtkUgweEIiFQkDA+2" . "0gnYweIICcgPtk0kDQAAAP8J0Q+2VRRmD27oi0UIZg9wzQDB4hAJ0Y1W9GYPbvFmD3DWADnQczkPEAAPEBgPEDhmD97BZg/e2mYP" @@ -2430,36 +2430,40 @@ class ImagePut { . "1GYP3tlmD3TQZg903A9U02YPdtVmRA/XwkWFwHUSSIPAEOvLikgCQTjLcwtIg8AESDnQcu/rHTjZcvGKSAFAOM5y6UA4+XLkighA" . "OM1y3UQ44XLYW15fXUFcQV1BXsM=") - ; C source code - https://godbolt.org/z/xj5seEhba + ; C source code - https://godbolt.org/z/GaEE4r3aW pixelsearch3 := this.Base64Code((A_PtrSize == 4) - ? "VTHSieVXi00MVlOLXRCLRRQp0A+E5QAAAIP4AXQbg/gCdAtmD25skwhmD3DdAGYPbnSTBGYPcNYAZg9uPJNmD3DPAIP4AXR6g/gC" - . "jXH0i0UIdGM58HM2DxAADyjgZg924WYP1/yF/w+FiQAAAA8o4mYPduBmD9f8hf91emYPdsNmD9f4hf91boPAEOvGg8ID6Xn///8P" - . "EAAPKOFmD3bgZg/X/IX/dU9mD3bCZg/X+IX/dUODwBA58HLbg8IC6Uz///+LRQiNcfQ58HMUDxAAZg92wWYP1/iF/3Ubg8AQ6+hC" - . "6Sj///+LNJM5MHQTQjtVFHXzg8AEOchzBjHS6/CJyFteX13D" - : "U0mJykiJ0THSTI1Z9ESJyCnQD4T2AAAASGPag/gBdB2D+AJ0DGZBD25smAhmD3DdAGZBD25smARmD3DVAGZBD24MmGYPcMkAg/gB" - . "dH+D+AJMidB0akw52HM7DxAADyjgZg924WYP19yF2w+FlQAAAA8o4mYPduBmD9fchdsPhYIAAABmD3bDZg/X2IXbdXZIg8AQ68CD" - . "wgPpcP///w8QAA8o4WYPduBmD9fchdt1VmYPdsJmD9fYhdt1SkiDwBBMOdhy2YPCAulB////TInQTDnYcxUPEABmD3bBZg/X2IXb" - . "dSJIg8AQ6+b/wukd////SP/CQYtckPw5GHQVRDnKcu9Ig8AESDnIcwcx0uvuSInIW8M=") - - ; C source code - https://godbolt.org/z/W54vWW7Gz + ? "VTHSieVXVlOD5PCD7BCLfQyNR/SJRCQEi0UUKdAPhBkBAACD+AF0PoP4AnQhg/gDvgMAAAAPTHQkDIl0JAyLdRBmD25klghmD3Dc" + . "AOsIx0QkDAIAAACLXRBmD25skwRmD3DVAOsIx0QkDAEAAACLdRBmD240lo0clolcJAhmD3DOAIP4AXR0g/gCi0UIdD6LTCQEOchz" + . "Lg8QAGYPdsFmD9fYDxAAidlmD3bCZg/X2A8QAAnLZg92w2YP1/AJ83V0g8AQ68qDwgPpS////4139Dnwcx8PEABmD3bBZg/XyA8Q" + . "AGYPdsJmD9fYCct1RoPAEOvdg8IC6R3///+LRQiNX/Q52HMUDxAAZg92wWYP1/CF9nUgg8AQ6+hC6fn+//+LTCQIiwyROQh0FEI5" + . "VCQMf+6DwAQ5+HMGMdLr74n4jWX0W15fXcM=" + : "QVVBVFVXVlO9AwAAAEmJykiJ0THSSI1x9ESJyCnQD4QEAQAAg/gBSGPadC6D+AJ0FWZBD25smAiD+ANED03dZg9w3QDrBkG7AgAA" + . "AGZBD25smARmD3DVAOsGQbsBAAAAZkEPbgyYSY08mGYPcMkAg/gBdHOD+AJMidB0Xkg58HMxDxAADyjhZg924GZED9fsDyjiZg92" + . "4GYPdsNmD9fcZkQP1+BECetECeN1c0iDwBDryoPCA+lf////DxAADyjhZg924GYPdsJmRA/X5GYP19hECeN1SUiDwBBIOfBy24PC" + . "Auky////TInQSDnwcxUPEABmD3bBZg/X2IXbdSFIg8AQ6+b/wukO////SP/Ci3SX/DkwdBVBOdN/8EiDwARIOchzBzHS6+5Iichb" + . "Xl9dQVxBXcM=") + + ; C source code - https://godbolt.org/z/oE5Knfc7W pixelsearch4 := this.Base64Code((A_PtrSize == 4) - ? "VTHSieVXVlOD5PCD7CCLdRCLTRSLRRgp0A+EDAIAAIP4AXQ6g/gCdB9mD25klghmD3DsAA8pbCQQZg9ubJEIZg9w3QAPKRwkZg9u" - . "ZJYEZg9uVJEEZg9w3ABmD3DqAGYPbiSWZg9uNJFmD3DUAGYPcOYAg/gBD4QdAQAAg/gCi0UID4SlAAAAi30MZg929o1f9DnYD4OL" - . "AAAADxAADyj6DyjIZg/e+GYP3sxmD3T6Zg90yA9Uz2YPds5mD9f5hf8PhSgBAAAPKMsPKPhmD97IZg/e/WYPdMtmD3T4D1TPZg92" - . "zmYP1/mF/w+F/wAAAA8oPCQPKEwkEGYP3vhmD97IZg90TCQQZg90xw9UyGYPds5mD9f5hf8PhdEAAACDwBDpbf///4PCA+no/v//" - . "i10MZg929oPrDDnYc1YPEAAPKPgPKMhmD978Zg/eymYPdMpmD3T4D1TPZg92zmYP1/mF/w+FhwAAAA8o+A8oy2YP3shmD979Zg90" - . "y2YPdMcPVMhmD3bOZg/X+YX/dWKDwBDrpoPCAul8/v//i30Mi0UIZg929o1f9DnYcy0PEAgPEAAPEDhmD97MZg/ewmYPdMJmD3TP" - . "D1TBZg92xmYP1/iF/3Ucg8AQ689C6Tj+//+J+zhclgJzIkI7VRh18oPABDtFDHM8ilABD7Z4AohUJBCKEIgUJDHS6986XJECctiK" - . "XCQQOFyWAXLOOlyRAXLIihwkOByWcsA6HJFyu+sDi0UMjWX0W15fXcM=" - : "VlNIg+xIDyk0JA8pfCQQRA8pRCQgRA8pTCQwi5wkgAAAAEmJykiJ0THSSI1x9EGJ20Ep0w+EEwIAAEhjwkGD+wF0NkGD+wJ0GGZB" - . "D250gAhmQQ9ubIEIZg9w5gBmD3D1AGZBD25cgARmQQ9ubIEEZg9w0wBmD3DtAGZBD24cgGZFD3bAZg9wywBmQQ9uHIFMidBmD3Db" - . "AEGD+wEPhFcBAABBg/sCD4QOAQAASDnwD4ObAAAADxAARA8oyQ8o+GZED97IZg/e+2ZED3TJZg90+EEPVPlmQQ92+GZED9ffRYXb" - . "D4UvAQAADyj6RA8oyGYP3vhmRA/ezWYPdPpmRA90yEEPVPlmQQ92+GZED9ffRYXbD4X/AAAARA8oyA8o/GYP3vhmRA/ezmYPdPxm" - . "QQ90wQ9Ux2ZBD3bAZkQP19hFhdsPhdAAAABIg8AQ6Vz///+DwgPp1/7//w8QAEQPKMgPKPhmRA/ey2YP3vlmD3T5ZkQPdMhBD1T5" - . "ZkEPdvhmRA/X30WF2w+FjAAAAEQPKMgPKPpmD974ZkQP3s1mD3T6ZkEPdMEPVMdmQQ92wGZED9fYRYXbdWFIg8AQSDnwcpmDwgLp" - . "aP7//w8QOEQPKM8PKMdmRA/ey2YP3sFmD3TBZkEPdPkPVMdmQQ92wGZED9fYRYXbdSJIg8AQSDnwcsn/wukq/v//RThUkAJzH0j/" - . "wjnacvJIg8AESDnIczVEilACRIpYATHSQIow6+RFOlSRAnLaRThckAFy00U6XJEBcsxBODSQcsZBOjSRcsDrA0iJyA8oNCQPKHwk" - . "EEQPKEQkIEQPKEwkMEiDxEhbXsM=") + ? "VTHAZg925InlV1ZTg+Twg+xAi1UYKcIPhFMCAACD+gF0YIP6AnQzi10Qg/oDuQMAAAAPTflmD25sgwiLXRRmD3D9AA8pfCQwZg9u" + . "fIMIZg9w3wAPKVwkEOsFvwIAAACLXRBmD25sgwSLXRRmD258gwRmD3DdAGYPcM8ADylMJCDrBb8BAAAAi10QjQyFAAAAAAHLiVwk" + . "DItdEGYPbiwLi10UZg9uPAuNNAtmD3DNAIl0JAiLdQhmD3DvAIP6AQ+ECwEAAItNDIPpDIP6Ag+EnAAAADnOD4OMAAAADxAGDyjw" + . "DyjQZg/e9WYP3tFmD3TwZg900Q9U1g8o8GYPdtRmD97zZg9082YP19oPKFQkIGYP3tBmD3TQD1TWDyh0JDBmD3bUZg/e8GYPdHQk" + . "MGYP19IPKFQkEIlUJARmD97QZg900A9U1mYPdtRmD9fSiRQki1QkBAnaCxQkD4XLAAAAg8YQ6Wz///+DwAPpo/7//2YPdv85znNQ" + . "DxAWDyjyDyjCZg/e9WYP3sFmD3TyZg90wQ9Uxg8odCQgZg92x2YP3vJmD3TyZg/X2A8owmYP3sNmD3TDD1TGZg92x2YP19AJ2nVo" + . "g8YQ66yDwALpQ/7//4tVDGYPdvaD6gw51nMtDxAWDxAGDxA+Zg/e1WYP3sFmD3TBZg901w9UwmYPdsZmD9fIhcl1JYPGEOvPQOkC" + . "/v//OFoCczr/RCQwg8IEg8AEi0wkMDnPf+mDxgQ7dQxzRIpGATHJil4CiUwkMItUJAyIRCQgigaIRCQQi0QkCOvQOlgCcsGKTCQg" + . "OEoBcrg6SAFys4pMJBA4CnKrOghyp+sDi3UMjWX0ifBbXl9dww==" + : "QVRVV1ZTSIPsUA8pNCQPKXwkEEQPKUQkIEQPKUwkMEQPKVQkQL8DAAAAZg9220mJ00iJyzHSSY1z9IuMJKAAAAAp0Q+EMgIAAIP5" + . "AUhjwnRGg/kCdCFmQQ9ufIAIZkEPbnSBCIP5A0QPTddmD3DvAGYPcP4A6wZBugIAAABmQQ9uZIAEZkEPbnSBBGYPcNQAZg9w9gDr" + . "BkG6AQAAAGZBD24kgGYPcMwAZkEPbiSBSInYZg9w5ACD+QEPhCIBAACD+QIPhKsAAABIOfAPg5oAAAAPEABEDyjIRA8owGZED97M" + . "ZkQP3sFmRA90yGZED3TBRQ9UwUQPKMhmRA92w2ZED97KZkQPdMpmRQ/X4EQPKMBmRA/exmZED3TARQ9UwUQPKMhmRA92w2ZED97N" + . "ZkQPdM1mQQ/XyEQPKMBmRA/ex0QJ4WZBD3TAQQ9UwWYPdsNmD9foCel0C8HiAkhj0unfAAAASIPAEOld////g8ID6cf+//9mRQ92" + . "wEg58HNcRA8QCEUPKNFBDyjBZkQP3tRmD97BZkUPdNFmD3TBQQ9UwkUPKNFmQQ92wGZED97WZg/X6EEPKMFmD97CZkUPdMpmD3TC" + . "QQ9UwWZBD3bAZg/XyAnpdYRIg8AQ65+DwgLpWf7//2ZFD3bJSDnwczlEDxAARQ8o0EEPKMBmRA/e1GYP3sFmD3TBZkUPdMJBD1TA" + . "ZkEPdsFmD9fIhckPhTn///9Ig8AQ68L/wukP/v//QTh0CAJzJv/DSIPBBEE52n/uSIPABEw52HM4QIpwAkCKeAFIidEx20CKKOvg" + . "QTp0CQJy00E4fAgBcsxBOnwJAXLFQTgsCHK/QTosCXK56wNMidgPKDQkDyh8JBBEDyhEJCBEDyhMJDBEDyhUJEBIg8RQW15fXUFc" + . "ww==") ; ------------------------------------------------------------------------------------------------------ @@ -2619,14 +2623,14 @@ class ImagePut { ; ----------------------- Machine code generated with MCode4GCC using gcc 13.2.0 ----------------------- - ; C source code - https://godbolt.org/z/ErbrhbWWE + ; C source code - https://godbolt.org/z/GYMPYv4qT pixelsearchall1 := this.Base64Code((A_PtrSize == 4) ? "VTHSieVXZg9uVRiLRRBWU4tdFGYPcMoAjXP0OfBzDw8QAGYPdsFmD9fIhcl0BY1IEOsVjUgQicjr4TnIdPiLfRg5OHQJg8AEOdhy" . "7usOO1UMcwaLfQiJBJdC6+lbidBeX13D" : "VlMxwESLVCQ4ZkEPbtJmD3DKAEmNWfRJOdhNjVgQcyNBDxAAZg92wWYP1/CF9nUTTYnY6+JNOdh09kU5EHQLSYPABE05yHLt6w45" . "0HMGicZMiQTx/8Dr51teww==") - ; C source code - https://godbolt.org/z/PssjWcE5M + ; C source code - https://godbolt.org/z/G5vYe5c8c pixelsearchall2 := this.Base64Code((A_PtrSize == 4) ? "VWYPduSJ5VdWU4Pk8IPsEItdGItNIItVKIpFHIhcJA8PttuLfRTB4xCIRCQOikUkiEwkDQ+2yY139IhUJAsPttLB4QgJ2ohEJAyK" . "RSwJyg+2TSQPttiBygAAAP+IRCQKweEIZg9u6jHSCcsPtk0cZg9wzQDB4RAJy2YPbvNmD3DWADl1EHMri0UQDxAADxAYDxA4Zg/e" @@ -2637,41 +2641,42 @@ class ImagePut { . "UBBzQEEPECAPKNEPKNxmD97UZg/e2GYPdNFmD3TcD1TTZg921WYP18qFyXUXSYnQ68lJOdB09kGKSAJAOM9zC0mDwARNOchy6esu" . "QDjpcvBBikgBQTjMcudEOOly4kGKCEE4znLaRDj5ctU58HMGicFMiQTL/8Drx1teX11BXEFdQV5BX8M=") - ; C source code - https://godbolt.org/z/zbPcWT1P3 + ; C source code - https://godbolt.org/z/Px5TE4MWW pixelsearchall3 := this.Base64Code((A_PtrSize == 4) - ? "VTHSMcmJ5VdWU4Pk8IPsEItdGItFHI0Eg4lEJASLRRSD6AyJRCQIi0UcKdCJRCQMD4QTAQAAg/gBdBuD+AJ0C2YPbmyTCGYPcN0A" - . "Zg9udJMEZg9w1gBmD248k4tFEGYPcM8Ag3wkDAF1C4t9FI139OmUAAAAg3wkDAJ0a4t8JAg5+HM6DxAADyjgZg924WYP1/SF9nUP" - . "DyjiZg924GYP1/SF9nQIjXAQiTQk63pmD3bDZg/X8IX2deyDwBDrvoPCA+lh////DxAADyjhZg924GYP1/SF9nXNZg92wmYP1/CF" - . "9nXBg8AQi3wkCDn4cteDwgLpMP///w8QAGYPdsFmD9f4hf91n4PAEDnwcupC6RT///+LPjk4dCKDxgSLfCQEOf5174PABDtFFHMd" - . "izwkOfgPhCz///+J3uvhO00McwaLfQiJBI9B69CNZfSJyFteX13D" - : "QVZBVUFUVVdWU0yLXCRgi2wkaEiJzonXMckx0k2NYfRBiepBKdIPhA4BAABIY8JBg/oBdB5Bg/oCdAxmQQ9ubIMIZg9w3QBmQQ9u" - . "bIMEZg9w1QBmQQ9uDINMicBmD3DJAEGD+gEPhI4AAABBg/oCdGhMOeBzOQ8QAA8o4GYPduFmD9fchdt1Dw8o4mYPduBmD9fchdt0" - . "BkyNaBDrfGYPdsNmD9fYhdt17kiDwBDrwoPCA+lp////DxAADyjhZg924GYP19yF23XOZg92wmYP19iF23XCSIPAEEw54HLZg8IC" - . "6Tr///8PEABmD3bBZg/X2IXbdaJIg8AQTDngcuj/wukb////RYs0m0Q5MHQdSP/DOety8EiDwARMOchzHEw56A+EOv///zHb6+Y5" - . "+XMHQYnOSokE9v/B69SJyFteX11BXEFdQV7D") - - ; C source code - https://godbolt.org/z/7oKb5Tnqd + ? "VTHSMcmJ5VdWU4Pk8IPsEItFFIPoDIlEJASLRRwp0IlEJAwPhDwBAACD+AF0PoP4AnQhg/gDuAMAAAAPTEQkCIlEJAiLRRhmD25k" + . "kAhmD3DcAOsIx0QkCAIAAACLRRhmD25skARmD3DVAOsIx0QkCAEAAACLRRiNBJCJBCSLRRhmD240kItFEGYPcM4Ag3wkDAF1C4t1" + . "FI1e9OmJAAAAg3wkDAJ0YIt8JAQ5+HMuDxAAZg92wWYP19gPEACJ32YPdsJmD9fYDxAACftmD3bDZg/X8AnzdQ2DwBDryoPCA+k2" + . "////jXAQ610PEABmD3bBZg/X8A8QAGYPdsJmD9fYCfN14YPAEIt8JAQ5+HLbg8IC6QT///8PEABmD3bBZg/X8IX2db+DwBA52HLq" + . "Quno/v//izwkizyfOTh0G0M5XCQIf++DwAQ7RRRzGjnwD4Q6////Mdvr5jtNDHMGi30IiQSPQevXjWX0ichbXl9dww==" + : "QVdBVkFVQVRVV1ZTQb4DAAAATItcJGhMiUQkWEiJzonXMckx0kmNafREi0QkcEEp0A+EKQEAAEGD+AFIY8J0MEGD+AJ0FmZBD25s" + . "gwhBg/gDRQ9N1mYPcN0A6wZBugIAAABmQQ9ubIMEZg9w1QDrBkG6AQAAAGZBD24Mg02NJINIi0QkWGYPcMkAQYP4AQ+EigAAAEGD" + . "+AJ0ZEg56HMxDxAADyjhZg924GZED9f8DyjiZg924GYPdsNmD9fcZkQP1+hECftECet1DkiDwBDryoPCA+lR////TI1oEOthDxAA" + . "DyjhZg924GYPdsJmRA/X7GYP19hECet13kiDwBBIOehy24PCAuke////DxAAZg92wWYP19iF23W+SIPAEEg56HLo/8Lp//7//0WL" + . "PJxEOTh0Hkj/w0E52n/vSIPABEw5yHMcTDnoD4Q9////Mdvr5Tn5cwdBic9KiQT+/8Hr04nIW15fXUFcQV1BXkFfww==") + + ; C source code - https://godbolt.org/z/T8KjEPb1z pixelsearchall4 := this.Base64Code((A_PtrSize == 4) - ? "VTHAZg920onlVzH/VlOD5PCD7DCLdRyJRCQsi0UgKfiJRCQoD4RCAgAAg/gBdECD+AJ0IotFGGYPbmS4CGYPcOwADylsJBBmD25s" - . "vghmD3DdAA8pHCSLRRhmD25MvgRmD25kuARmD3DpAGYPcNwAi0UYZg9uJLiLRRBmD3DMAGYPbiS+Zg9w5ACDfCQoAXULi1UUg+oM" - . "6UYBAACDfCQoAnULi00UjVH06fUAAACLVRSD6gw50A+DiwAAAA8QAA8o+Q8o8GYP3vhmD970Zg90+WYPdPAPVPdmD3byZg/XzoXJ" - . "dSUPKPMPKPhmD97wZg/e/WYPdPNmD3T4D1T3Zg928mYP186FyXQMjUgQiUwkIOkBAQAADyg8JA8odCQQZg/e+GYP3vBmD3R0JBBm" - . "D3THD1TwZg928mYP186FyXXKg8AQ6W3///+DxwPpzf7//w8QAA8o+A8o8GYP3vxmD97xZg908WYPdPgPVPdmD3byZg/XzoXJdZIP" - . "KPgPKPNmD97wZg/e/WYPdPNmD3THD1TwZg928mYP186FyQ+Faf///4PAEDnQcqiDxwLpbf7//w8QMA8QAA8QOGYP3vRmD97BZg90" - . "wWYPdPcPVMZmD3YFAAAAAGYP18iFyQ+FKv///4PAEDnQcslH6TD+//+LVCQgOdAPhJL+//+KUAKIVCQnilABiFQkJooQiFQkJTHS" - . "O1UgdQqDwAQ7RRRy0etQi10YikwkJzhMkwJyQDpMlgJyOopMJCY4TJMBcjA6TJYBciqKTCQlOAyTciE6DJZyHItMJCw7TQxzCotN" - . "CItcJCyJBJmLTCQsQYlMJCxC66GLRCQsjWX0W15fXcM=" - : "QVdBVkFVQVRVV1ZTSIPsaA8pdCQQDyl8JCBEDylEJDBEDylMJEBEDylUJFBmD3bSTIuUJNAAAACLhCTgAAAASIu0JNgAAABJjQSC" - . "SImMJLAAAABJjXn0SIkEJImUJLgAAAAx0kyJhCTAAAAARTHAi5wk4AAAACnTD4RSAgAASGPCg/sBdDOD+wJ0F2ZBD258gghmD250" - . "hghmD3DvAGYPcP4AZkEPbmSCBGYPbnSGBGYPcNwAZg9w9gBmQQ9uJIJmD3DMAGYPbiSGSIuEJMAAAABmD3DkAGZFD3bJg/sBD4Rl" - . "AQAAg/sCD4QYAQAASDn4D4OiAAAADxAARA8oyUQPKMBmRA/eyGZED97EZkQPdMlmRA90wEUPVMFmRA92wmZBD9fIhcl1LkQPKMNE" - . "DyjIZkQP3sBmRA/ezmZED3TDZkQPdMhFD1TBZkQPdsJmQQ/XyIXJdA5IjUgQSIlMJAjpHgEAAEQPKMhEDyjFZkQP3sBmRA/ez2ZE" - . "D3TFZkEPdMFBD1TAZg92wmYP18iFyXXGSIPAEOlV////g8ID6c/+//8PEABEDyjIRA8owGZED97MZkQP3sFmRA90wWZED3TIRQ9U" - . "wWZED3bCZkEP18iFyXWERA8oyEQPKMNmRA/ewGZED97OZkQPdMNmQQ90wUEPVMBmD3bCZg/XyIXJD4VU////SIPAEEg5+HKWg8IC" - . "6V3+//9EDxAARQ8o0EEPKMBmRA/e1GYP3sFmD3TBZkUPdMJBD1TAZkEPdsFmD9fIhckPhRD///9Ig8AQSDn4csT/wuka/v//SItM" - . "JAhIOcgPhHP+//9AimgCRIpgAUmJ80yJ0USKKEyLNCRMOfF1C0iDwARMOchyz+tIQDhpAnI4QTprAnIyRDhhAXIsRTpjAXImRDgp" - . "ciFFOityHEQ7hCS4AAAAcw9Mi7QksAAAAEWJx0uJBP5B/8BIg8EESYPDBOukDyh0JBAPKHwkIESJwEQPKEQkMEQPKEwkQEQPKFQk" - . "UEiDxGhbXl9dQVxBXUFeQV/D") + ? "VWYPdtKJ5VdWMfZTMduD5PCD7ECJXCQ0i0UgKfCJRCQ8D4R3AgAAg/gBdGOD+AJ0OIP4A7gDAAAAD0xEJDiJRCQ4i0UYZg9uZLAI" + . "i0UcZg9w7AAPKWwkIGYPbmywCGYPcN0ADykcJOsIx0QkOAIAAACLRRhmD25ksASLRRxmD25MsARmD3DcAGYPcOkA6wjHRCQ4AQAA" + . "AItdGI0EtQAAAACLVRiLfRABw2YPbiQCiVwkGItdHGYPcMwAjRQDZg9uJAOJVCQUZg9w5ACDfCQ8AYtFFHUIg+gM6SoBAACDfCQ8" + . "Ao1Q9I1Y9A+E2gAAADnfc3YPEAcPKPgPKPBmD978Zg/e8WYPdPhmD3TxD1T3Dyj4Zg928mYP3vtmD3T7Zg/Xzg8o8GYP3vVmD3Tw" + . "D1T3Dyh8JCBmD3byZg/e+GYPdHwkIGYP18YPKDQkCchmD97wZg908A9U92YPdvJmD9fWCdB1DYPHEOuGg8YD6aj+//+NRxCJRCQQ" + . "6dAAAAAPEDcPKP4PKMZmD978Zg/ewWYPdP5mD3TBD1THDyj+Zg92wmYP3v1mD3T+Zg/XyA8oxmYP3sNmD3TDD1THZg92wmYP18AJ" + . "yHWrg8cQOddysIPGAulE/v//DxA3DxAHDxA/Zg/e9GYP3sFmD3TBZg909w9UxmYPdgUAAAAAZg/X0IXSD4Vs////g8cQOcdyyUbp" + . "B/7//4tEJBA5xw+Erv7//4pHAjHJi1QkFIlMJDCIRCQfikcBiEQkHooHiEQkHYtEJBiLXCQwOVwkOH8Kg8cEO30UcsDrS4pMJB84" + . "SAJyNjpKAnIxilwkHjhYAXIoOloBciOKTCQdOAhyGzoKcheLTCQ0O00McwqLTQiLXCQ0iTyZ/0QkNP9EJDCDwASDwgTroYtEJDSN" + . "ZfRbXl9dww==" + : "QVdBVkFVQVRVV1ZTSIPseA8pdCQgDyl8JDBEDylEJEBEDylMJFBEDylUJGBFMdJmD3bSSImMJMAAAABNic5Mi4wk6AAAAEyJhCTQ" + . "AAAATIuEJOAAAABJjXb0iZQkyAAAADHSRIucJPAAAABBKdMPhHgCAABBg/sBSGPCdEtBg/sCdCZmQQ9ufIAIZkEPbnSBCEGD+wO/" + . "AwAAAA9N32YPcO8AZg9w/gDrBbsCAAAAZkEPbmSABGZBD250gQRmD3DcAGYPcPYA6wW7AQAAAGZBD24kgGYPcMwAZkEPbiSBjQSV" + . "AAAAAEiYSIlEJBBIi4Qk0AAAAGYPcOQAZkUPdslBg/sBD4RTAQAAQYP7Ag+EBQEAAEg58A+DjgAAAA8QAEQPKMhEDyjAZkQP3sxm" + . "RA/ewWZED3TIZkQPdMFFD1TBRA8oyGZED3bCZkQP3stmRA90y2ZBD9foRA8owGZED97GZkQPdMBFD1TBRA8oyGZED3bCZkQP3s1m" + . "RA90zWZBD9fIRA8owGZED97HCelmQQ90wEEPVMFmD3bCZg/X+An5dRFIg8AQ6Wn///+DwgPpsv7//0iNeBBIiXwkGOnYAAAARA8Q" + . "AEUPKMhBDyjAZkQP3sxmD97BZkUPdMhmD3TBQQ9UwUUPKMhmD3bCZkQP3s5mD9f4QQ8owGYP3sNmRQ90wWYPdMNBD1TAZg92wmYP" + . "18gJ+XWeSIPAEEg58HKjg8IC6T/+//9EDxAARQ8o0EEPKMBmRA/e1GYP3sFmD3TBZkUPdMJBD1TAZkEPdsFmD9fIhckPhVr///9I" + . "g8AQSDnwcsT/wun8/f//SIt8JBhIOfgPhIT+//8x/0CKaAJEimABRIooSItMJBCJfCQMi3wkDDn7fwtIg8AETDnwcsvrTkE4bAgC" + . "cj1BOmwJAnI2RThkCAFyL0U6ZAkBcihFOCwIciJFOiwJchxEO5QkyAAAAHMPSIu8JMAAAABFiddKiQT/Qf/C/0QkDEiDwQTrnw8o" + . "dCQgDyh8JDBEidBEDyhEJEBEDyhMJFBEDyhUJGBIg8R4W15fXUFcQV1BXkFfww==") ; ------------------------------------------------------------------------------------------------------ diff --git a/ImagePut.ahk b/ImagePut.ahk index d7ed4b95..932b0f78 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2414,12 +2414,12 @@ class ImagePut { ; ----------------------- Machine code generated with MCode4GCC using gcc 13.2.0 ----------------------- - ; C source code - https://godbolt.org/z/6jPnc6b5s + ; C source code - https://godbolt.org/z/zr71creqn pixelsearch1 := this.Base64Code((A_PtrSize == 4) ? "VYnlVotNEItVDFOLRQhmD27RjVr0Zg9wygA52HMbDxAAZg92wWYP1/CF9nUMg8AQ6+g5CHQHg8AEOdBy9VteXcM=" : "ZkEPbtBIichIjUr0Zg9wygBIOchzIA8QAGYPdsFmRA/XyEWFyXUPSIPAEOvkRDkAdAlIg8AESDnQcvLD") - ; C source code - https://godbolt.org/z/7fv3P6KTb + ; C source code - https://godbolt.org/z/65Yvsvs1G pixelsearch2 := this.Base64Code((A_PtrSize == 4) ? "VWYPduSJ5VdWU4Pk8IPsEIpFFItdEItNGItVHIt1DIt9IIhEJA6KRSSIXCQPD7bbiEwkDcHjEA+2yYhEJAsPtkUgweEIiFQkDA+2" . "0gnYweIICcgPtk0kDQAAAP8J0Q+2VRRmD27oi0UIZg9wzQDB4hAJ0Y1W9GYPbvFmD3DWADnQczkPEAAPEBgPEDhmD97BZg/e2mYP" @@ -2430,36 +2430,40 @@ class ImagePut { . "1GYP3tlmD3TQZg903A9U02YPdtVmRA/XwkWFwHUSSIPAEOvLikgCQTjLcwtIg8AESDnQcu/rHTjZcvGKSAFAOM5y6UA4+XLkighA" . "OM1y3UQ44XLYW15fXUFcQV1BXsM=") - ; C source code - https://godbolt.org/z/xj5seEhba + ; C source code - https://godbolt.org/z/GaEE4r3aW pixelsearch3 := this.Base64Code((A_PtrSize == 4) - ? "VTHSieVXi00MVlOLXRCLRRQp0A+E5QAAAIP4AXQbg/gCdAtmD25skwhmD3DdAGYPbnSTBGYPcNYAZg9uPJNmD3DPAIP4AXR6g/gC" - . "jXH0i0UIdGM58HM2DxAADyjgZg924WYP1/yF/w+FiQAAAA8o4mYPduBmD9f8hf91emYPdsNmD9f4hf91boPAEOvGg8ID6Xn///8P" - . "EAAPKOFmD3bgZg/X/IX/dU9mD3bCZg/X+IX/dUODwBA58HLbg8IC6Uz///+LRQiNcfQ58HMUDxAAZg92wWYP1/iF/3Ubg8AQ6+hC" - . "6Sj///+LNJM5MHQTQjtVFHXzg8AEOchzBjHS6/CJyFteX13D" - : "U0mJykiJ0THSTI1Z9ESJyCnQD4T2AAAASGPag/gBdB2D+AJ0DGZBD25smAhmD3DdAGZBD25smARmD3DVAGZBD24MmGYPcMkAg/gB" - . "dH+D+AJMidB0akw52HM7DxAADyjgZg924WYP19yF2w+FlQAAAA8o4mYPduBmD9fchdsPhYIAAABmD3bDZg/X2IXbdXZIg8AQ68CD" - . "wgPpcP///w8QAA8o4WYPduBmD9fchdt1VmYPdsJmD9fYhdt1SkiDwBBMOdhy2YPCAulB////TInQTDnYcxUPEABmD3bBZg/X2IXb" - . "dSJIg8AQ6+b/wukd////SP/CQYtckPw5GHQVRDnKcu9Ig8AESDnIcwcx0uvuSInIW8M=") - - ; C source code - https://godbolt.org/z/W54vWW7Gz + ? "VTHSieVXVlOD5PCD7BCLfQyNR/SJRCQEi0UUKdAPhBkBAACD+AF0PoP4AnQhg/gDvgMAAAAPTHQkDIl0JAyLdRBmD25klghmD3Dc" + . "AOsIx0QkDAIAAACLXRBmD25skwRmD3DVAOsIx0QkDAEAAACLdRBmD240lo0clolcJAhmD3DOAIP4AXR0g/gCi0UIdD6LTCQEOchz" + . "Lg8QAGYPdsFmD9fYDxAAidlmD3bCZg/X2A8QAAnLZg92w2YP1/AJ83V0g8AQ68qDwgPpS////4139Dnwcx8PEABmD3bBZg/XyA8Q" + . "AGYPdsJmD9fYCct1RoPAEOvdg8IC6R3///+LRQiNX/Q52HMUDxAAZg92wWYP1/CF9nUgg8AQ6+hC6fn+//+LTCQIiwyROQh0FEI5" + . "VCQMf+6DwAQ5+HMGMdLr74n4jWX0W15fXcM=" + : "QVVBVFVXVlO9AwAAAEmJykiJ0THSSI1x9ESJyCnQD4QEAQAAg/gBSGPadC6D+AJ0FWZBD25smAiD+ANED03dZg9w3QDrBkG7AgAA" + . "AGZBD25smARmD3DVAOsGQbsBAAAAZkEPbgyYSY08mGYPcMkAg/gBdHOD+AJMidB0Xkg58HMxDxAADyjhZg924GZED9fsDyjiZg92" + . "4GYPdsNmD9fcZkQP1+BECetECeN1c0iDwBDryoPCA+lf////DxAADyjhZg924GYPdsJmRA/X5GYP19hECeN1SUiDwBBIOfBy24PC" + . "Auky////TInQSDnwcxUPEABmD3bBZg/X2IXbdSFIg8AQ6+b/wukO////SP/Ci3SX/DkwdBVBOdN/8EiDwARIOchzBzHS6+5Iichb" + . "Xl9dQVxBXcM=") + + ; C source code - https://godbolt.org/z/oE5Knfc7W pixelsearch4 := this.Base64Code((A_PtrSize == 4) - ? "VTHSieVXVlOD5PCD7CCLdRCLTRSLRRgp0A+EDAIAAIP4AXQ6g/gCdB9mD25klghmD3DsAA8pbCQQZg9ubJEIZg9w3QAPKRwkZg9u" - . "ZJYEZg9uVJEEZg9w3ABmD3DqAGYPbiSWZg9uNJFmD3DUAGYPcOYAg/gBD4QdAQAAg/gCi0UID4SlAAAAi30MZg929o1f9DnYD4OL" - . "AAAADxAADyj6DyjIZg/e+GYP3sxmD3T6Zg90yA9Uz2YPds5mD9f5hf8PhSgBAAAPKMsPKPhmD97IZg/e/WYPdMtmD3T4D1TPZg92" - . "zmYP1/mF/w+F/wAAAA8oPCQPKEwkEGYP3vhmD97IZg90TCQQZg90xw9UyGYPds5mD9f5hf8PhdEAAACDwBDpbf///4PCA+no/v//" - . "i10MZg929oPrDDnYc1YPEAAPKPgPKMhmD978Zg/eymYPdMpmD3T4D1TPZg92zmYP1/mF/w+FhwAAAA8o+A8oy2YP3shmD979Zg90" - . "y2YPdMcPVMhmD3bOZg/X+YX/dWKDwBDrpoPCAul8/v//i30Mi0UIZg929o1f9DnYcy0PEAgPEAAPEDhmD97MZg/ewmYPdMJmD3TP" - . "D1TBZg92xmYP1/iF/3Ucg8AQ689C6Tj+//+J+zhclgJzIkI7VRh18oPABDtFDHM8ilABD7Z4AohUJBCKEIgUJDHS6986XJECctiK" - . "XCQQOFyWAXLOOlyRAXLIihwkOByWcsA6HJFyu+sDi0UMjWX0W15fXcM=" - : "VlNIg+xIDyk0JA8pfCQQRA8pRCQgRA8pTCQwi5wkgAAAAEmJykiJ0THSSI1x9EGJ20Ep0w+EEwIAAEhjwkGD+wF0NkGD+wJ0GGZB" - . "D250gAhmQQ9ubIEIZg9w5gBmD3D1AGZBD25cgARmQQ9ubIEEZg9w0wBmD3DtAGZBD24cgGZFD3bAZg9wywBmQQ9uHIFMidBmD3Db" - . "AEGD+wEPhFcBAABBg/sCD4QOAQAASDnwD4ObAAAADxAARA8oyQ8o+GZED97IZg/e+2ZED3TJZg90+EEPVPlmQQ92+GZED9ffRYXb" - . "D4UvAQAADyj6RA8oyGYP3vhmRA/ezWYPdPpmRA90yEEPVPlmQQ92+GZED9ffRYXbD4X/AAAARA8oyA8o/GYP3vhmRA/ezmYPdPxm" - . "QQ90wQ9Ux2ZBD3bAZkQP19hFhdsPhdAAAABIg8AQ6Vz///+DwgPp1/7//w8QAEQPKMgPKPhmRA/ey2YP3vlmD3T5ZkQPdMhBD1T5" - . "ZkEPdvhmRA/X30WF2w+FjAAAAEQPKMgPKPpmD974ZkQP3s1mD3T6ZkEPdMEPVMdmQQ92wGZED9fYRYXbdWFIg8AQSDnwcpmDwgLp" - . "aP7//w8QOEQPKM8PKMdmRA/ey2YP3sFmD3TBZkEPdPkPVMdmQQ92wGZED9fYRYXbdSJIg8AQSDnwcsn/wukq/v//RThUkAJzH0j/" - . "wjnacvJIg8AESDnIczVEilACRIpYATHSQIow6+RFOlSRAnLaRThckAFy00U6XJEBcsxBODSQcsZBOjSRcsDrA0iJyA8oNCQPKHwk" - . "EEQPKEQkIEQPKEwkMEiDxEhbXsM=") + ? "VTHAZg925InlV1ZTg+Twg+xAi1UYKcIPhFMCAACD+gF0YIP6AnQzi10Qg/oDuQMAAAAPTflmD25sgwiLXRRmD3D9AA8pfCQwZg9u" + . "fIMIZg9w3wAPKVwkEOsFvwIAAACLXRBmD25sgwSLXRRmD258gwRmD3DdAGYPcM8ADylMJCDrBb8BAAAAi10QjQyFAAAAAAHLiVwk" + . "DItdEGYPbiwLi10UZg9uPAuNNAtmD3DNAIl0JAiLdQhmD3DvAIP6AQ+ECwEAAItNDIPpDIP6Ag+EnAAAADnOD4OMAAAADxAGDyjw" + . "DyjQZg/e9WYP3tFmD3TwZg900Q9U1g8o8GYPdtRmD97zZg9082YP19oPKFQkIGYP3tBmD3TQD1TWDyh0JDBmD3bUZg/e8GYPdHQk" + . "MGYP19IPKFQkEIlUJARmD97QZg900A9U1mYPdtRmD9fSiRQki1QkBAnaCxQkD4XLAAAAg8YQ6Wz///+DwAPpo/7//2YPdv85znNQ" + . "DxAWDyjyDyjCZg/e9WYP3sFmD3TyZg90wQ9Uxg8odCQgZg92x2YP3vJmD3TyZg/X2A8owmYP3sNmD3TDD1TGZg92x2YP19AJ2nVo" + . "g8YQ66yDwALpQ/7//4tVDGYPdvaD6gw51nMtDxAWDxAGDxA+Zg/e1WYP3sFmD3TBZg901w9UwmYPdsZmD9fIhcl1JYPGEOvPQOkC" + . "/v//OFoCczr/RCQwg8IEg8AEi0wkMDnPf+mDxgQ7dQxzRIpGATHJil4CiUwkMItUJAyIRCQgigaIRCQQi0QkCOvQOlgCcsGKTCQg" + . "OEoBcrg6SAFys4pMJBA4CnKrOghyp+sDi3UMjWX0ifBbXl9dww==" + : "QVRVV1ZTSIPsUA8pNCQPKXwkEEQPKUQkIEQPKUwkMEQPKVQkQL8DAAAAZg9220mJ00iJyzHSSY1z9IuMJKAAAAAp0Q+EMgIAAIP5" + . "AUhjwnRGg/kCdCFmQQ9ufIAIZkEPbnSBCIP5A0QPTddmD3DvAGYPcP4A6wZBugIAAABmQQ9uZIAEZkEPbnSBBGYPcNQAZg9w9gDr" + . "BkG6AQAAAGZBD24kgGYPcMwAZkEPbiSBSInYZg9w5ACD+QEPhCIBAACD+QIPhKsAAABIOfAPg5oAAAAPEABEDyjIRA8owGZED97M" + . "ZkQP3sFmRA90yGZED3TBRQ9UwUQPKMhmRA92w2ZED97KZkQPdMpmRQ/X4EQPKMBmRA/exmZED3TARQ9UwUQPKMhmRA92w2ZED97N" + . "ZkQPdM1mQQ/XyEQPKMBmRA/ex0QJ4WZBD3TAQQ9UwWYPdsNmD9foCel0C8HiAkhj0unfAAAASIPAEOld////g8ID6cf+//9mRQ92" + . "wEg58HNcRA8QCEUPKNFBDyjBZkQP3tRmD97BZkUPdNFmD3TBQQ9UwkUPKNFmQQ92wGZED97WZg/X6EEPKMFmD97CZkUPdMpmD3TC" + . "QQ9UwWZBD3bAZg/XyAnpdYRIg8AQ65+DwgLpWf7//2ZFD3bJSDnwczlEDxAARQ8o0EEPKMBmRA/e1GYP3sFmD3TBZkUPdMJBD1TA" + . "ZkEPdsFmD9fIhckPhTn///9Ig8AQ68L/wukP/v//QTh0CAJzJv/DSIPBBEE52n/uSIPABEw52HM4QIpwAkCKeAFIidEx20CKKOvg" + . "QTp0CQJy00E4fAgBcsxBOnwJAXLFQTgsCHK/QTosCXK56wNMidgPKDQkDyh8JBBEDyhEJCBEDyhMJDBEDyhUJEBIg8RQW15fXUFc" + . "ww==") ; ------------------------------------------------------------------------------------------------------ @@ -2619,14 +2623,14 @@ class ImagePut { ; ----------------------- Machine code generated with MCode4GCC using gcc 13.2.0 ----------------------- - ; C source code - https://godbolt.org/z/ErbrhbWWE + ; C source code - https://godbolt.org/z/GYMPYv4qT pixelsearchall1 := this.Base64Code((A_PtrSize == 4) ? "VTHSieVXZg9uVRiLRRBWU4tdFGYPcMoAjXP0OfBzDw8QAGYPdsFmD9fIhcl0BY1IEOsVjUgQicjr4TnIdPiLfRg5OHQJg8AEOdhy" . "7usOO1UMcwaLfQiJBJdC6+lbidBeX13D" : "VlMxwESLVCQ4ZkEPbtJmD3DKAEmNWfRJOdhNjVgQcyNBDxAAZg92wWYP1/CF9nUTTYnY6+JNOdh09kU5EHQLSYPABE05yHLt6w45" . "0HMGicZMiQTx/8Dr51teww==") - ; C source code - https://godbolt.org/z/PssjWcE5M + ; C source code - https://godbolt.org/z/G5vYe5c8c pixelsearchall2 := this.Base64Code((A_PtrSize == 4) ? "VWYPduSJ5VdWU4Pk8IPsEItdGItNIItVKIpFHIhcJA8PttuLfRTB4xCIRCQOikUkiEwkDQ+2yY139IhUJAsPttLB4QgJ2ohEJAyK" . "RSwJyg+2TSQPttiBygAAAP+IRCQKweEIZg9u6jHSCcsPtk0cZg9wzQDB4RAJy2YPbvNmD3DWADl1EHMri0UQDxAADxAYDxA4Zg/e" @@ -2637,41 +2641,42 @@ class ImagePut { . "UBBzQEEPECAPKNEPKNxmD97UZg/e2GYPdNFmD3TcD1TTZg921WYP18qFyXUXSYnQ68lJOdB09kGKSAJAOM9zC0mDwARNOchy6esu" . "QDjpcvBBikgBQTjMcudEOOly4kGKCEE4znLaRDj5ctU58HMGicFMiQTL/8Drx1teX11BXEFdQV5BX8M=") - ; C source code - https://godbolt.org/z/zbPcWT1P3 + ; C source code - https://godbolt.org/z/Px5TE4MWW pixelsearchall3 := this.Base64Code((A_PtrSize == 4) - ? "VTHSMcmJ5VdWU4Pk8IPsEItdGItFHI0Eg4lEJASLRRSD6AyJRCQIi0UcKdCJRCQMD4QTAQAAg/gBdBuD+AJ0C2YPbmyTCGYPcN0A" - . "Zg9udJMEZg9w1gBmD248k4tFEGYPcM8Ag3wkDAF1C4t9FI139OmUAAAAg3wkDAJ0a4t8JAg5+HM6DxAADyjgZg924WYP1/SF9nUP" - . "DyjiZg924GYP1/SF9nQIjXAQiTQk63pmD3bDZg/X8IX2deyDwBDrvoPCA+lh////DxAADyjhZg924GYP1/SF9nXNZg92wmYP1/CF" - . "9nXBg8AQi3wkCDn4cteDwgLpMP///w8QAGYPdsFmD9f4hf91n4PAEDnwcupC6RT///+LPjk4dCKDxgSLfCQEOf5174PABDtFFHMd" - . "izwkOfgPhCz///+J3uvhO00McwaLfQiJBI9B69CNZfSJyFteX13D" - : "QVZBVUFUVVdWU0yLXCRgi2wkaEiJzonXMckx0k2NYfRBiepBKdIPhA4BAABIY8JBg/oBdB5Bg/oCdAxmQQ9ubIMIZg9w3QBmQQ9u" - . "bIMEZg9w1QBmQQ9uDINMicBmD3DJAEGD+gEPhI4AAABBg/oCdGhMOeBzOQ8QAA8o4GYPduFmD9fchdt1Dw8o4mYPduBmD9fchdt0" - . "BkyNaBDrfGYPdsNmD9fYhdt17kiDwBDrwoPCA+lp////DxAADyjhZg924GYP19yF23XOZg92wmYP19iF23XCSIPAEEw54HLZg8IC" - . "6Tr///8PEABmD3bBZg/X2IXbdaJIg8AQTDngcuj/wukb////RYs0m0Q5MHQdSP/DOety8EiDwARMOchzHEw56A+EOv///zHb6+Y5" - . "+XMHQYnOSokE9v/B69SJyFteX11BXEFdQV7D") - - ; C source code - https://godbolt.org/z/7oKb5Tnqd + ? "VTHSMcmJ5VdWU4Pk8IPsEItFFIPoDIlEJASLRRwp0IlEJAwPhDwBAACD+AF0PoP4AnQhg/gDuAMAAAAPTEQkCIlEJAiLRRhmD25k" + . "kAhmD3DcAOsIx0QkCAIAAACLRRhmD25skARmD3DVAOsIx0QkCAEAAACLRRiNBJCJBCSLRRhmD240kItFEGYPcM4Ag3wkDAF1C4t1" + . "FI1e9OmJAAAAg3wkDAJ0YIt8JAQ5+HMuDxAAZg92wWYP19gPEACJ32YPdsJmD9fYDxAACftmD3bDZg/X8AnzdQ2DwBDryoPCA+k2" + . "////jXAQ610PEABmD3bBZg/X8A8QAGYPdsJmD9fYCfN14YPAEIt8JAQ5+HLbg8IC6QT///8PEABmD3bBZg/X8IX2db+DwBA52HLq" + . "Quno/v//izwkizyfOTh0G0M5XCQIf++DwAQ7RRRzGjnwD4Q6////Mdvr5jtNDHMGi30IiQSPQevXjWX0ichbXl9dww==" + : "QVdBVkFVQVRVV1ZTQb4DAAAATItcJGhMiUQkWEiJzonXMckx0kmNafREi0QkcEEp0A+EKQEAAEGD+AFIY8J0MEGD+AJ0FmZBD25s" + . "gwhBg/gDRQ9N1mYPcN0A6wZBugIAAABmQQ9ubIMEZg9w1QDrBkG6AQAAAGZBD24Mg02NJINIi0QkWGYPcMkAQYP4AQ+EigAAAEGD" + . "+AJ0ZEg56HMxDxAADyjhZg924GZED9f8DyjiZg924GYPdsNmD9fcZkQP1+hECftECet1DkiDwBDryoPCA+lR////TI1oEOthDxAA" + . "DyjhZg924GYPdsJmRA/X7GYP19hECet13kiDwBBIOehy24PCAuke////DxAAZg92wWYP19iF23W+SIPAEEg56HLo/8Lp//7//0WL" + . "PJxEOTh0Hkj/w0E52n/vSIPABEw5yHMcTDnoD4Q9////Mdvr5Tn5cwdBic9KiQT+/8Hr04nIW15fXUFcQV1BXkFfww==") + + ; C source code - https://godbolt.org/z/T8KjEPb1z pixelsearchall4 := this.Base64Code((A_PtrSize == 4) - ? "VTHAZg920onlVzH/VlOD5PCD7DCLdRyJRCQsi0UgKfiJRCQoD4RCAgAAg/gBdECD+AJ0IotFGGYPbmS4CGYPcOwADylsJBBmD25s" - . "vghmD3DdAA8pHCSLRRhmD25MvgRmD25kuARmD3DpAGYPcNwAi0UYZg9uJLiLRRBmD3DMAGYPbiS+Zg9w5ACDfCQoAXULi1UUg+oM" - . "6UYBAACDfCQoAnULi00UjVH06fUAAACLVRSD6gw50A+DiwAAAA8QAA8o+Q8o8GYP3vhmD970Zg90+WYPdPAPVPdmD3byZg/XzoXJ" - . "dSUPKPMPKPhmD97wZg/e/WYPdPNmD3T4D1T3Zg928mYP186FyXQMjUgQiUwkIOkBAQAADyg8JA8odCQQZg/e+GYP3vBmD3R0JBBm" - . "D3THD1TwZg928mYP186FyXXKg8AQ6W3///+DxwPpzf7//w8QAA8o+A8o8GYP3vxmD97xZg908WYPdPgPVPdmD3byZg/XzoXJdZIP" - . "KPgPKPNmD97wZg/e/WYPdPNmD3THD1TwZg928mYP186FyQ+Faf///4PAEDnQcqiDxwLpbf7//w8QMA8QAA8QOGYP3vRmD97BZg90" - . "wWYPdPcPVMZmD3YFAAAAAGYP18iFyQ+FKv///4PAEDnQcslH6TD+//+LVCQgOdAPhJL+//+KUAKIVCQnilABiFQkJooQiFQkJTHS" - . "O1UgdQqDwAQ7RRRy0etQi10YikwkJzhMkwJyQDpMlgJyOopMJCY4TJMBcjA6TJYBciqKTCQlOAyTciE6DJZyHItMJCw7TQxzCotN" - . "CItcJCyJBJmLTCQsQYlMJCxC66GLRCQsjWX0W15fXcM=" - : "QVdBVkFVQVRVV1ZTSIPsaA8pdCQQDyl8JCBEDylEJDBEDylMJEBEDylUJFBmD3bSTIuUJNAAAACLhCTgAAAASIu0JNgAAABJjQSC" - . "SImMJLAAAABJjXn0SIkEJImUJLgAAAAx0kyJhCTAAAAARTHAi5wk4AAAACnTD4RSAgAASGPCg/sBdDOD+wJ0F2ZBD258gghmD250" - . "hghmD3DvAGYPcP4AZkEPbmSCBGYPbnSGBGYPcNwAZg9w9gBmQQ9uJIJmD3DMAGYPbiSGSIuEJMAAAABmD3DkAGZFD3bJg/sBD4Rl" - . "AQAAg/sCD4QYAQAASDn4D4OiAAAADxAARA8oyUQPKMBmRA/eyGZED97EZkQPdMlmRA90wEUPVMFmRA92wmZBD9fIhcl1LkQPKMNE" - . "DyjIZkQP3sBmRA/ezmZED3TDZkQPdMhFD1TBZkQPdsJmQQ/XyIXJdA5IjUgQSIlMJAjpHgEAAEQPKMhEDyjFZkQP3sBmRA/ez2ZE" - . "D3TFZkEPdMFBD1TAZg92wmYP18iFyXXGSIPAEOlV////g8ID6c/+//8PEABEDyjIRA8owGZED97MZkQP3sFmRA90wWZED3TIRQ9U" - . "wWZED3bCZkEP18iFyXWERA8oyEQPKMNmRA/ewGZED97OZkQPdMNmQQ90wUEPVMBmD3bCZg/XyIXJD4VU////SIPAEEg5+HKWg8IC" - . "6V3+//9EDxAARQ8o0EEPKMBmRA/e1GYP3sFmD3TBZkUPdMJBD1TAZkEPdsFmD9fIhckPhRD///9Ig8AQSDn4csT/wuka/v//SItM" - . "JAhIOcgPhHP+//9AimgCRIpgAUmJ80yJ0USKKEyLNCRMOfF1C0iDwARMOchyz+tIQDhpAnI4QTprAnIyRDhhAXIsRTpjAXImRDgp" - . "ciFFOityHEQ7hCS4AAAAcw9Mi7QksAAAAEWJx0uJBP5B/8BIg8EESYPDBOukDyh0JBAPKHwkIESJwEQPKEQkMEQPKEwkQEQPKFQk" - . "UEiDxGhbXl9dQVxBXUFeQV/D") + ? "VWYPdtKJ5VdWMfZTMduD5PCD7ECJXCQ0i0UgKfCJRCQ8D4R3AgAAg/gBdGOD+AJ0OIP4A7gDAAAAD0xEJDiJRCQ4i0UYZg9uZLAI" + . "i0UcZg9w7AAPKWwkIGYPbmywCGYPcN0ADykcJOsIx0QkOAIAAACLRRhmD25ksASLRRxmD25MsARmD3DcAGYPcOkA6wjHRCQ4AQAA" + . "AItdGI0EtQAAAACLVRiLfRABw2YPbiQCiVwkGItdHGYPcMwAjRQDZg9uJAOJVCQUZg9w5ACDfCQ8AYtFFHUIg+gM6SoBAACDfCQ8" + . "Ao1Q9I1Y9A+E2gAAADnfc3YPEAcPKPgPKPBmD978Zg/e8WYPdPhmD3TxD1T3Dyj4Zg928mYP3vtmD3T7Zg/Xzg8o8GYP3vVmD3Tw" + . "D1T3Dyh8JCBmD3byZg/e+GYPdHwkIGYP18YPKDQkCchmD97wZg908A9U92YPdvJmD9fWCdB1DYPHEOuGg8YD6aj+//+NRxCJRCQQ" + . "6dAAAAAPEDcPKP4PKMZmD978Zg/ewWYPdP5mD3TBD1THDyj+Zg92wmYP3v1mD3T+Zg/XyA8oxmYP3sNmD3TDD1THZg92wmYP18AJ" + . "yHWrg8cQOddysIPGAulE/v//DxA3DxAHDxA/Zg/e9GYP3sFmD3TBZg909w9UxmYPdgUAAAAAZg/X0IXSD4Vs////g8cQOcdyyUbp" + . "B/7//4tEJBA5xw+Erv7//4pHAjHJi1QkFIlMJDCIRCQfikcBiEQkHooHiEQkHYtEJBiLXCQwOVwkOH8Kg8cEO30UcsDrS4pMJB84" + . "SAJyNjpKAnIxilwkHjhYAXIoOloBciOKTCQdOAhyGzoKcheLTCQ0O00McwqLTQiLXCQ0iTyZ/0QkNP9EJDCDwASDwgTroYtEJDSN" + . "ZfRbXl9dww==" + : "QVdBVkFVQVRVV1ZTSIPseA8pdCQgDyl8JDBEDylEJEBEDylMJFBEDylUJGBFMdJmD3bSSImMJMAAAABNic5Mi4wk6AAAAEyJhCTQ" + . "AAAATIuEJOAAAABJjXb0iZQkyAAAADHSRIucJPAAAABBKdMPhHgCAABBg/sBSGPCdEtBg/sCdCZmQQ9ufIAIZkEPbnSBCEGD+wO/" + . "AwAAAA9N32YPcO8AZg9w/gDrBbsCAAAAZkEPbmSABGZBD250gQRmD3DcAGYPcPYA6wW7AQAAAGZBD24kgGYPcMwAZkEPbiSBjQSV" + . "AAAAAEiYSIlEJBBIi4Qk0AAAAGYPcOQAZkUPdslBg/sBD4RTAQAAQYP7Ag+EBQEAAEg58A+DjgAAAA8QAEQPKMhEDyjAZkQP3sxm" + . "RA/ewWZED3TIZkQPdMFFD1TBRA8oyGZED3bCZkQP3stmRA90y2ZBD9foRA8owGZED97GZkQPdMBFD1TBRA8oyGZED3bCZkQP3s1m" + . "RA90zWZBD9fIRA8owGZED97HCelmQQ90wEEPVMFmD3bCZg/X+An5dRFIg8AQ6Wn///+DwgPpsv7//0iNeBBIiXwkGOnYAAAARA8Q" + . "AEUPKMhBDyjAZkQP3sxmD97BZkUPdMhmD3TBQQ9UwUUPKMhmD3bCZkQP3s5mD9f4QQ8owGYP3sNmRQ90wWYPdMNBD1TAZg92wmYP" + . "18gJ+XWeSIPAEEg58HKjg8IC6T/+//9EDxAARQ8o0EEPKMBmRA/e1GYP3sFmD3TBZkUPdMJBD1TAZkEPdsFmD9fIhckPhVr///9I" + . "g8AQSDnwcsT/wun8/f//SIt8JBhIOfgPhIT+//8x/0CKaAJEimABRIooSItMJBCJfCQMi3wkDDn7fwtIg8AETDnwcsvrTkE4bAgC" + . "cj1BOmwJAnI2RThkCAFyL0U6ZAkBcihFOCwIciJFOiwJchxEO5QkyAAAAHMPSIu8JMAAAABFiddKiQT/Qf/C/0QkDEiDwQTrnw8o" + . "dCQgDyh8JDBEidBEDyhEJEBEDyhMJFBEDyhUJGBIg8R4W15fXUFcQV1BXkFfww==") ; ------------------------------------------------------------------------------------------------------ From 83c8c4fee1cd63596b371081aeb89887a40d5f5b Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 23 Sep 2023 18:58:39 -0400 Subject: [PATCH 464/492] Fix tooltip dissapprearing! --- ImagePut (for v1).ahk | 6 +++--- ImagePut.ahk | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 3b298904..22079ab0 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -3413,10 +3413,10 @@ class ImagePut { DllCall("SendMessage", "ptr", tt, "uint", 1044, "ptr", text_color, "ptr", 0) ; Destroy tooltip after 7 seconds of the last showing. - SetTimer Tooltip, -7000 - goto default + SetTimer Reset_Tooltip, -7000 + return - Tooltip: + Reset_Tooltip: Tooltip,,,, 16 return } diff --git a/ImagePut.ahk b/ImagePut.ahk index 932b0f78..bd9628b1 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -3413,14 +3413,14 @@ class ImagePut { DllCall("SendMessage", "ptr", tt, "uint", 1044, "ptr", text_color, "ptr", 0) ; Destroy tooltip after 7 seconds of the last showing. - SetTimer Tooltip.bind(,,, 16), -7000 + static Reset_Tooltip := Tooltip.bind(,,, 16) + SetTimer Reset_Tooltip, -7000 } - ; WM_APP - Animate GIFs if (uMsg = 0x8000) { ; Thanks tmplinshi, Teadrinker - https://www.autohotkey.com/boards/viewtopic.php?f=76&t=83358 From 66a59eece313aedc46d8a86fb2f5c982769a2967 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sat, 30 Sep 2023 15:34:18 -0400 Subject: [PATCH 465/492] AdjustWindowRectEx uses a bool --- ImagePut (for v1).ahk | 2 +- ImagePut.ahk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 22079ab0..fedc76bc 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2992,7 +2992,7 @@ class ImagePut { NumPut(x2, rect, 8, "int") NumPut(y2, rect, 12, "int") - DllCall("AdjustWindowRectEx", "ptr", &rect, "uint", style, "uint", 0, "uint", styleEx) + DllCall("AdjustWindowRectEx", "ptr", &rect, "uint", style, "int", 0, "uint", styleEx) try dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") hwnd := DllCall("CreateWindowEx" diff --git a/ImagePut.ahk b/ImagePut.ahk index bd9628b1..30adad3c 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2992,7 +2992,7 @@ class ImagePut { NumPut("int", x2, rect, 8) NumPut("int", y2, rect, 12) - DllCall("AdjustWindowRectEx", "ptr", rect, "uint", style, "uint", 0, "uint", styleEx) + DllCall("AdjustWindowRectEx", "ptr", rect, "uint", style, "int", 0, "uint", styleEx) try dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") hwnd := DllCall("CreateWindowEx" From 281ffdb9fe43acf900d6c6767dd77dd4ea28b5f6 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 3 Oct 2023 00:07:22 -0400 Subject: [PATCH 466/492] Add relative to window syntax show(), to_window() --- ImagePut (for v1).ahk | 28 ++++++++++++++++++++++++++-- ImagePut.ahk | 30 +++++++++++++++++++++++++++--- 2 files changed, 53 insertions(+), 5 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index fedc76bc..bb2f8856 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2299,7 +2299,7 @@ class ImagePut { return DllCall(code, "int") } - + CPUID() { static cpuid := 0 @@ -2629,7 +2629,7 @@ class ImagePut { . "7usOO1UMcwaLfQiJBJdC6+lbidBeX13D" : "VlMxwESLVCQ4ZkEPbtJmD3DKAEmNWfRJOdhNjVgQcyNBDxAAZg92wWYP1/CF9nUTTYnY6+JNOdh09kU5EHQLSYPABE05yHLt6w45" . "0HMGicZMiQTx/8Dr51teww==") - + ; C source code - https://godbolt.org/z/G5vYe5c8c pixelsearchall2 := this.Base64Code((A_PtrSize == 4) ? "VWYPduSJ5VdWU4Pk8IPsEItdGItNIItVKIpFHIhcJA8PttuLfRTB4xCIRCQOikUkiEwkDQ+2yY139IhUJAsPttLB4QgJ2ohEJAyK" @@ -2978,6 +2978,18 @@ class ImagePut { x := IsObject(pos) && pos.HasKey(1) ? pos[1] : 0.5*(ScreenWidth - w) y := IsObject(pos) && pos.HasKey(2) ? pos[2] : 0.5*(ScreenHeight - h) + ; Adjust x and y if a relative to window position is given. + if IsObject(pos) && pos.HasKey(5) && (WinExist(pos[5]) || DllCall("IsWindow", "ptr", pos[5])) { + try dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") + pos[5] := (hwnd := WinExist(pos[5])) ? hwnd : pos[5] + VarSetCapacity(rect, 16, 0) + DllCall("GetClientRect", "ptr", pos[5], "ptr", &rect) + DllCall("ClientToScreen", "ptr", pos[5], "ptr", &rect) + try DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") + x += NumGet(rect, 0, "int") + y += NumGet(rect, 4, "int") + } + ; Resolve dependent coordinates first, coordinates second, and distances last. x2 := Round(x + w) y2 := Round(y + h) @@ -3067,6 +3079,18 @@ class ImagePut { x := IsObject(pos) && pos.HasKey(1) ? pos[1] : 0.5*(ScreenWidth - w) y := IsObject(pos) && pos.HasKey(2) ? pos[2] : 0.5*(ScreenHeight - h) + ; Adjust x and y if a relative to window position is given. + if IsObject(pos) && pos.Has(5) && (WinExist(pos[5]) || DllCall("IsWindow", "ptr", pos[5])) { + try dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") + pos[5] := (hwnd := WinExist(pos[5])) ? hwnd : pos[5] + VarSetCapacity(rect, 16, 0) + DllCall("GetClientRect", "ptr", pos[5], "ptr", &rect) + DllCall("ClientToScreen", "ptr", pos[5], "ptr", &rect) + try DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") + x += NumGet(rect, 0, "int") + y += NumGet(rect, 4, "int") + } + ; Resolve dependent coordinates first, coordinates second, and distances last. x2 := Round(x + w) y2 := Round(y + h) diff --git a/ImagePut.ahk b/ImagePut.ahk index 30adad3c..cdd09bea 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2629,7 +2629,7 @@ class ImagePut { . "7usOO1UMcwaLfQiJBJdC6+lbidBeX13D" : "VlMxwESLVCQ4ZkEPbtJmD3DKAEmNWfRJOdhNjVgQcyNBDxAAZg92wWYP1/CF9nUTTYnY6+JNOdh09kU5EHQLSYPABE05yHLt6w45" . "0HMGicZMiQTx/8Dr51teww==") - + ; C source code - https://godbolt.org/z/G5vYe5c8c pixelsearchall2 := this.Base64Code((A_PtrSize == 4) ? "VWYPduSJ5VdWU4Pk8IPsEItdGItNIItVKIpFHIhcJA8PttuLfRTB4xCIRCQOikUkiEwkDQ+2yY139IhUJAsPttLB4QgJ2ohEJAyK" @@ -2679,7 +2679,7 @@ class ImagePut { . "dCQgDyh8JDBEidBEDyhEJEBEDyhMJFBEDyhUJGBIg8R4W15fXUFcQV1BXkFfww==") ; ------------------------------------------------------------------------------------------------------ - + ; Global number of addresses (matching searches) to allocate. limit := 256 @@ -2689,7 +2689,7 @@ class ImagePut { ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. if (option == 1) - count := DllCall(pixelsearchall1, "ptr", result, "uint", limit, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "cdecl uint") + count := DllCall(pixelsearchall1, "ptr", result, "uint", limit, "ptr", this.ptr, "ptr", this.ptr + this.size, "uint", color, "cdecl uint") if (option == 2) { r := ((color & 0xFF0000) >> 16) @@ -2978,6 +2978,18 @@ class ImagePut { x := IsObject(pos) && pos.Has(1) ? pos[1] : 0.5*(ScreenWidth - w) y := IsObject(pos) && pos.Has(2) ? pos[2] : 0.5*(ScreenHeight - h) + ; Adjust x and y if a relative to window position is given. + if IsObject(pos) && pos.Has(5) && WinExist(pos[5]) { + try dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") + WinGetClientPos &xr, &yr,,, pos[5] + try DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") + x += xr + y += yr + } + + + + ; Resolve dependent coordinates first, coordinates second, and distances last. x2 := Round(x + w) y2 := Round(y + h) @@ -3067,6 +3079,18 @@ class ImagePut { x := IsObject(pos) && pos.Has(1) ? pos[1] : 0.5*(ScreenWidth - w) y := IsObject(pos) && pos.Has(2) ? pos[2] : 0.5*(ScreenHeight - h) + ; Adjust x and y if a relative to window position is given. + if IsObject(pos) && pos.Has(5) && WinExist(pos[5]) { + try dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") + WinGetClientPos &xr, &yr,,, pos[5] + try DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") + x += xr + y += yr + } + + + + ; Resolve dependent coordinates first, coordinates second, and distances last. x2 := Round(x + w) y2 := Round(y + h) From 1c6c82b88de27e1a81635cc022d1905a86f54111 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Tue, 3 Oct 2023 00:31:49 -0400 Subject: [PATCH 467/492] [x, y, w, h, r] where r is a window handle --- ImagePut (for v1).ahk | 23 ++++++++++++++++++----- ImagePut.ahk | 15 ++++++++++++++- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index bb2f8856..4f70a727 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -1118,16 +1118,29 @@ class ImagePut { from_screenshot(image) { ; Thanks tic - https://www.autohotkey.com/boards/viewtopic.php?t=6517 - if !IsObject(image) { + ; Allow the image to be a window handle. + if !IsObject(image) and WinExist(image) || DllCall("IsWindow", "ptr", image) { try dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") - hwnd := WinExist(image) + image := (hwnd := WinExist(image)) ? hwnd : image VarSetCapacity(rect, 16, 0) - DllCall("GetClientRect", "ptr", hwnd, "ptr", &rect) - DllCall("ClientToScreen", "ptr", hwnd, "ptr", &rect) + DllCall("GetClientRect", "ptr", image, "ptr", &rect) + DllCall("ClientToScreen", "ptr", image, "ptr", &rect) try DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") image := [NumGet(rect, 0, "int"), NumGet(rect, 4, "int"), NumGet(rect, 8, "int"), NumGet(rect, 12, "int")] } + ; Adjust coordinates relative to specified window. + if image.haskey(5) && (WinExist(image[5]) || DllCall("IsWindow", "ptr", image[5])) { + try dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") + image[5] := (hwnd := WinExist(image[5])) ? hwnd : image[5] + VarSetCapacity(rect, 16, 0) + DllCall("GetClientRect", "ptr", image[5], "ptr", &rect) + DllCall("ClientToScreen", "ptr", image[5], "ptr", &rect) + try DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") + image[1] += NumGet(rect, 0, "int") + image[2] += NumGet(rect, 4, "int") + } + ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") VarSetCapacity(bi, 40, 0) ; sizeof(bi) = 40 @@ -3080,7 +3093,7 @@ class ImagePut { y := IsObject(pos) && pos.HasKey(2) ? pos[2] : 0.5*(ScreenHeight - h) ; Adjust x and y if a relative to window position is given. - if IsObject(pos) && pos.Has(5) && (WinExist(pos[5]) || DllCall("IsWindow", "ptr", pos[5])) { + if IsObject(pos) && pos.HasKey(5) && (WinExist(pos[5]) || DllCall("IsWindow", "ptr", pos[5])) { try dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") pos[5] := (hwnd := WinExist(pos[5])) ? hwnd : pos[5] VarSetCapacity(rect, 16, 0) diff --git a/ImagePut.ahk b/ImagePut.ahk index cdd09bea..6523950e 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -1118,7 +1118,8 @@ class ImagePut { static from_screenshot(image) { ; Thanks tic - https://www.autohotkey.com/boards/viewtopic.php?t=6517 - if !IsObject(image) { + ; Allow the image to be a window handle. + if !IsObject(image) and WinExist(image) { try dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") WinGetClientPos &x, &y, &w, &h, image try DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") @@ -1128,6 +1129,18 @@ class ImagePut { + ; Adjust coordinates relative to specified window. + if image.Has(5) and WinExist(image[5]) { + try dpi := DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr") + WinGetClientPos &xr, &yr,,, image[5] + try DllCall("SetThreadDpiAwarenessContext", "ptr", dpi, "ptr") + image[1] += xr + image[2] += yr + } + + + + ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr") bi := Buffer(40, 0) ; sizeof(bi) = 40 From 70f3372fe3430138a3089206054494bad2e345c7 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Wed, 4 Oct 2023 20:42:36 -0400 Subject: [PATCH 468/492] Improve ImageSearch --- ImagePut (for v1).ahk | 16 +++++++++------- ImagePut.ahk | 18 ++++++++++-------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 4f70a727..70db202c 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2840,12 +2840,13 @@ class ImagePut { ImageSearch(image) { ; C source code - https://godbolt.org/z/qPodGdP1d code := this.Base64Code((A_PtrSize == 4) - ? "VYnlV1ZTg+wUi0UMi1UYi00IjTyFAAAAAItFECtFHA+vxwNFCIlF6ItFDCnQiUXkjQSVAAAAAIlF7ItF6DnBc2eLRRSLADkBdAmL" - . "RRSAeAMAdVCJyCtFCDHSwfgC93UMOVXkfD4x0otFFInLiVXwi3XwO3UcdDyLVeyJ3gHCiVXgi1XgOdBzFIB4AwB0BosWORB1D4PA" - . "BIPGBOvl/0XwAfvrzIPBBOuSi0UQD6/HA0UIicGDxBSJyFteX13D" - : "QVdBVkFVQVRVV1ZTi1wkcItEJGhIjSyFAAAAAEGJ0kSJwkmJyynaRInXQQ+v0inHSI00kUg58XNjQYsBOQF0B0GAeQMAdU9Iicgx" - . "0kwp2EjB+AJB9/I513w8TInIRTHkMdI52nQ+RYnlTI00KE6NLKlMOfBzGYB4AwB0CUWLfQBEOTh1EUiDwARJg8UE6+L/wkUB1OvM" - . "SIPBBOuYRQ+vwkuNDINIichbXl9dQVxBXUFeQV/D") + ? "VYnlV1ZTg+wgi0Uki1UYi30Ui00gD6/Qi3UIix8Pr0UMAcqJXeSLHJeLfQwByItVECtVHIlF7MHnAold4ItdDA+v1ytdGANVCIlV" + . "3Ild2ItF3DnGc3CLReyLTeA5DIZ1YInwK0UIMdLB+AL3dQw5VdhyTotF5DkGdUeLRRgx0onxiVXwweACiUXoi0UUi13wO10cdDyL" + . "VeiJywHCiVXUi1XUOdBzFIB4AwB0BosTORB1D4PABIPDBOvl/0XwAfnrzIPGBOuJi0UQD6/HA0UIicaDxCCJ8FteX13D" + : "QVdBVkFVQVRVV1ZTSIPsKIuEJKgAAACLnCSQAAAARYshQYnSicJJicuLjCSgAAAAD6/TRInXQQ+vwinfiXwkHEgBykWLLJFEicIr" + . "lCSYAAAASAHIQQ+v0kiJRCQITInZSY0sk0g56Q+DgAAAAEiLRCQIRDksgXVsSInIMdJMKdhIwfgCQffyOVQkHHJXRDkhdVKJ3jH/" + . "MdJIjQS1AAAAAEiJRCQQTInIO5QkmAAAAHRESIt0JBBBif5OjTSxTI08MEw5+HMXgHgDAHQHQYs2OTB1EUiDwARJg8YE6+T/wkQB" + . "1+vESIPBBOl3////RQ+vwkuNDINIichIg8QoW15fXUFcQV1BXkFfww==") ; Convert image to a buffer object. if !(IsObject(image) && ObjHasKey(image, "ptr") && ObjHasKey(image, "size")) @@ -2853,7 +2854,8 @@ class ImagePut { ; Search for the address of the first matching image. address := DllCall(code, "ptr", this.ptr, "uint", this.width, "uint", this.height - , "ptr", image.ptr, "uint", image.width, "uint", image.height, "cdecl ptr") + , "ptr", image.ptr, "uint", image.width, "uint", image.height, "uint", image.width//2, "uint", image.height//2 + , "cdecl ptr") ; Compare the address to the out-of-bounds limit. if (address == this.ptr + this.size) diff --git a/ImagePut.ahk b/ImagePut.ahk index 6523950e..ddedf889 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2838,14 +2838,15 @@ class ImagePut { } ImageSearch(image) { - ; C source code - https://godbolt.org/z/qPodGdP1d + ; C source code - https://godbolt.org/z/cKxrrT4ss code := this.Base64Code((A_PtrSize == 4) - ? "VYnlV1ZTg+wUi0UMi1UYi00IjTyFAAAAAItFECtFHA+vxwNFCIlF6ItFDCnQiUXkjQSVAAAAAIlF7ItF6DnBc2eLRRSLADkBdAmL" - . "RRSAeAMAdVCJyCtFCDHSwfgC93UMOVXkfD4x0otFFInLiVXwi3XwO3UcdDyLVeyJ3gHCiVXgi1XgOdBzFIB4AwB0BosWORB1D4PA" - . "BIPGBOvl/0XwAfvrzIPBBOuSi0UQD6/HA0UIicGDxBSJyFteX13D" - : "QVdBVkFVQVRVV1ZTi1wkcItEJGhIjSyFAAAAAEGJ0kSJwkmJyynaRInXQQ+v0inHSI00kUg58XNjQYsBOQF0B0GAeQMAdU9Iicgx" - . "0kwp2EjB+AJB9/I513w8TInIRTHkMdI52nQ+RYnlTI00KE6NLKlMOfBzGYB4AwB0CUWLfQBEOTh1EUiDwARJg8UE6+L/wkUB1OvM" - . "SIPBBOuYRQ+vwkuNDINIichbXl9dQVxBXUFeQV/D") + ? "VYnlV1ZTg+wgi0Uki1UYi30Ui00gD6/Qi3UIix8Pr0UMAcqJXeSLHJeLfQwByItVECtVHIlF7MHnAold4ItdDA+v1ytdGANVCIlV" + . "3Ild2ItF3DnGc3CLReyLTeA5DIZ1YInwK0UIMdLB+AL3dQw5VdhyTotF5DkGdUeLRRgx0onxiVXwweACiUXoi0UUi13wO10cdDyL" + . "VeiJywHCiVXUi1XUOdBzFIB4AwB0BosTORB1D4PABIPDBOvl/0XwAfnrzIPGBOuJi0UQD6/HA0UIicaDxCCJ8FteX13D" + : "QVdBVkFVQVRVV1ZTSIPsKIuEJKgAAACLnCSQAAAARYshQYnSicJJicuLjCSgAAAAD6/TRInXQQ+vwinfiXwkHEgBykWLLJFEicIr" + . "lCSYAAAASAHIQQ+v0kiJRCQITInZSY0sk0g56Q+DgAAAAEiLRCQIRDksgXVsSInIMdJMKdhIwfgCQffyOVQkHHJXRDkhdVKJ3jH/" + . "MdJIjQS1AAAAAEiJRCQQTInIO5QkmAAAAHRESIt0JBBBif5OjTSxTI08MEw5+HMXgHgDAHQHQYs2OTB1EUiDwARJg8YE6+T/wkQB" + . "1+vESIPBBOl3////RQ+vwkuNDINIichIg8QoW15fXUFcQV1BXkFfww==") ; Convert image to a buffer object. if !(IsObject(image) && ObjHasOwnProp(image, "ptr") && ObjHasOwnProp(image, "size")) @@ -2853,7 +2854,8 @@ class ImagePut { ; Search for the address of the first matching image. address := DllCall(code, "ptr", this.ptr, "uint", this.width, "uint", this.height - , "ptr", image.ptr, "uint", image.width, "uint", image.height, "cdecl ptr") + , "ptr", image.ptr, "uint", image.width, "uint", image.height, "uint", image.width//2, "uint", image.height//2 + , "cdecl ptr") ; Compare the address to the out-of-bounds limit. if (address == this.ptr + this.size) From 42f309b53e9c91edeab5d846a249c924c0f209ae Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 6 Oct 2023 11:51:08 -0400 Subject: [PATCH 469/492] Add count property --- ImagePut (for v1).ahk | 2 ++ ImagePut.ahk | 2 ++ 2 files changed, 4 insertions(+) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 70db202c..31ff9b86 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -2829,6 +2829,7 @@ class ImagePut { ; Create an array of [x, y] coordinates. xys := [] + xys.count := count loop % count { address := NumGet(result, A_PtrSize*(A_Index-1), "ptr") offset := (address - this.ptr) // 4 @@ -2902,6 +2903,7 @@ class ImagePut { ; Create an array of [x, y] coordinates. xys := [] + xys.count := count loop % count { address := NumGet(result, A_PtrSize*(A_Index-1), "ptr") offset := (address - this.ptr) // 4 diff --git a/ImagePut.ahk b/ImagePut.ahk index ddedf889..05b9da07 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2829,6 +2829,7 @@ class ImagePut { ; Create an array of [x, y] coordinates. xys := [] + xys.count := count loop count { address := NumGet(result, A_PtrSize * (A_Index-1), "ptr") offset := (address - this.ptr) // 4 @@ -2902,6 +2903,7 @@ class ImagePut { ; Create an array of [x, y] coordinates. xys := [] + xys.count := count loop count { address := NumGet(result, A_PtrSize*(A_Index-1), "ptr") offset := (address - this.ptr) // 4 From 9ee8be93a264d396a148df65ca26e5e370e4531a Mon Sep 17 00:00:00 2001 From: "Gunwoo Gim (il debole)" Date: Thu, 14 Dec 2023 13:40:37 +0900 Subject: [PATCH 470/492] Experiment with ImageSearchAll with tolerance to color variation --- ImagePut.ahk | 70 ++++++++++++----- source/imagesearch2.c | 156 +++++++++++++++++++++++++++++++++++++ source/imagesearchall2.c | 164 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 372 insertions(+), 18 deletions(-) create mode 100644 source/imagesearch2.c create mode 100644 source/imagesearchall2.c diff --git a/ImagePut.ahk b/ImagePut.ahk index 05b9da07..e4152954 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2839,6 +2839,12 @@ class ImagePut { } ImageSearch(image) { + ; FIXME Since I haven't install the GCC libraries for 32bit libraries and build 32bit binary, it won't work on 32-bit systems, Thank you for your understanding! + if ( A_PtrSize == 4 ) { + MsgBox("Since I haven't install the GCC libraries for 32bit libraries and build 32bit binary, it won't work on 32-bit systems, Thank you for your understanding!") + return False + } + ; C source code - https://godbolt.org/z/cKxrrT4ss code := this.Base64Code((A_PtrSize == 4) ? "VYnlV1ZTg+wgi0Uki1UYi30Ui00gD6/Qi3UIix8Pr0UMAcqJXeSLHJeLfQwByItVECtVHIlF7MHnAold4ItdDA+v1ytdGANVCIlV" @@ -2867,47 +2873,75 @@ class ImagePut { return [mod(offset, this.width), offset // this.width] } - ImageSearchAll(image) { + ImageSearchAll(image, variation := 0) { + ; FIXME Since I haven't install the GCC libraries for 32bit libraries and build 32bit binary, it won't work on 32-bit systems, Thank you for your understanding! + if ( A_PtrSize == 4 ) { + MsgBox("Since I haven't install the GCC libraries for 32bit libraries and build 32bit binary, it won't work on 32-bit systems, Thank you for your understanding!") + return False + } + ; C source code - https://godbolt.org/z/qPodGdP1d code := this.Base64Code((A_PtrSize == 4) ? "VYnlV1ZTg+wUi0UMi1UYi00IjTyFAAAAAItFECtFHA+vxwNFCIlF6ItFDCnQiUXkjQSVAAAAAIlF7ItF6DnBc2eLRRSLADkBdAmL" . "RRSAeAMAdVCJyCtFCDHSwfgC93UMOVXkfD4x0otFFInLiVXwi3XwO3UcdDyLVeyJ3gHCiVXgi1XgOdBzFIB4AwB0BosWORB1D4PA" . "BIPGBOvl/0XwAfvrzIPBBOuSi0UQD6/HA0UIicGDxBSJyFteX13D" - : "QVdBVkFVQVRVV1ZTSIPsGEUx20SLpCSYAAAAi4QkgAAAAESLlCSQAAAASIu8JIgAAABEKeBBD6/BSInLidZMicFNjSyARInIRCnQ" - . "iUQkDEqNBJUAAAAASIkEJEw56XN0iwc5AXQGgH8DAHViSInIMdJMKcBIwfgCQffxOVQkDHxNSIn4Me0x0kQ54nQyTIs8JEGJ7k6N" - . "NLFJAcdMOfhzGIB4AwB0CEWLFkQ5EHUgSIPABEmDxgTr4//CRAHN68lBOfNzB0SJ2EiJDMNB/8NIg8EE64dEidhIg8QYW15fXUFc" - . "QV1BXkFfww==") + : "QVdBVkFVQVRVV1ZTSIPsSIuEJNAAAACLtCTIAAAARImMJKgAAABED7eMJNgAAABIiYwkkAAAAImUJJgAAABMiYQkoAAAAIXAD4Xa" + . "AwAARIuUJMAAAACJ8kSLnCTAAAAAweoCD6+UJMAAAACLjCTAAAAARA+v1kHB6wJIi7wkuAAAAESJ2EgBwkWJ0EiNFJdMAcFIjRyP" + . "SDnaD4MOAwAARIuEJMAAAABB0ehJweACSo0MAkg50XcW6ZMDAAAPH0AASIPCBEg50Q+G1AIAAIB6AwB07UiJ0EgrhCS4AAAAMdJI" + . "wfgC97QkwAAAAGaJVCQwRA+3wg+30InRD6+MJMAAAACJVCQ0TAHBSMHhAkiLhCS4AAAASIu8JKAAAABEi6wkqAAAAEQrrCTAAAAA" + . "iwQIi4wksAAAACnxD6+MJKgAAABIjSyPSDnvD4PtAgAAD6+UJKgAAABJiftFicrHRCQsAAAAAEH32kwBwkiNPJUAAAAAi5QkwAAA" + . "AEiNXwFIiXwkCEiDxwJIiVwkEIucJKgAAABIiXwkIEiNPJUAAAAASYncSIlcJDiLnCTAAAAASSnUjVP/ScHkAkiNHJUAAAAAD7bQ" + . "ZolUJCgPttTB6BAPtsBIiRwkMduJVCQcZolEJCrrFg8fgAAAAABMAxwkMdtJOesPgwoBAABEOet37EiLRCQIQQ+2FAMPt0QkKCnQ" + . "ZkE5wXMKZkQ50A+CyAAAAEiLRCQQQQ+2FAMPt0QkHCnQZkE5wXMKZkQ50A+CpwAAAEiLRCQgQQ+2FAMPt0QkKinQZkE5wXMKZkQ5" + . "0A+ChgAAAEiLhCS4AAAATInaRTH/hfYPhNsAAABMjQQ4STnAdxvpzQAAAA8fRAAASIPABEiDwgRJOcAPhqcAAACAeAMAdOkPtghE" + . "D7YyRCnxZkE5yXMGZkQ50XIwD7ZIAUQPtnIBRCnxZkE5yXMGZkQ50XIYD7ZIAkQPtnICRCnxZkE5yXOpZkQ50XOjSYPDBIPDATHA" + . "O5wkqAAAAA9D2Ek56w+C9v7//4tEJCxIi7QkkAAAAAHASI0EhkiJhCSQAAAASInGi0QkMMHgEAtEJDSJBotEJCxIg8RIW15fXUFc" + . "QV1BXkFfw0GDxwFMAeJEOf4PhSX///+LTCQsOYwkmAAAAHYwTInYSCuEJKAAAABIwfgCSJlI93wkOGYPbsJIi5QkkAAAAGYPOiLA" + . "AY0ECWYP1gSCg0QkLAFJAfsDnCTAAAAA6Uv///9MAcJIOdMPhwH9//9Ii7wkuAAAADHJRTHAMdJmRIlEJDCAfA8DAIlUJDQPhTv9" + . "//+LjCTAAAAAQY1T/0QrlCTAAAAASMHgAkwB0kj32EQp2UiNFJdIweECSPfZSYnQSQHAchXrUWYuDx+EAAAAAABIg+oESTnQcz6A" + . "egMAdPHpr/z//w8fQABBicBBwegQZkSJRCQw6br8///HRCQsAAAAAEiLtCSQAAAA6c/+//9IicrpTf///0gByuug") + ;: "QVdBVkFVQVRVV1ZTSIPsGEUx20SLpCSYAAAAi4QkgAAAAESLlCSQAAAASIu8JIgAAABEKeBBD6/BSInLidZMicFNjSyARInIRCnQ" + ;. "iUQkDEqNBJUAAAAASIkEJEw56XN0iwc5AXQGgH8DAHViSInIMdJMKcBIwfgCQffxOVQkDHxNSIn4Me0x0kQ54nQyTIs8JEGJ7k6N" + ;. "NLFJAcdMOfhzGIB4AwB0CEWLFkQ5EHUgSIPABEmDxgTr4//CRAHN68lBOfNzB0SJ2EiJDMNB/8NIg8EE64dEidhIg8QYW15fXUFc" + ;. "QV1BXkFfww==") ; Convert image to a buffer object. if !(IsObject(image) && ObjHasOwnProp(image, "ptr") && ObjHasOwnProp(image, "size")) image := ImagePutBuffer(image) + ; Check if the object has the coordinates. + coord_focus := ObjHasOwnProp(image, "coord_focus") ? image.coord_focus : 0 + ; Search for the address of the first matching image. capacity := 256 - result := Buffer(A_PtrSize * capacity) + result := Buffer(2 * 4 * capacity + 4) count := DllCall(code, "ptr", result, "uint", capacity , "ptr", this.ptr, "uint", this.width, "uint", this.height - , "ptr", image.ptr, "uint", image.width, "uint", image.height, "cdecl uint") + , "ptr", image.ptr, "uint", image.width, "uint", image.height + , "UInt", coord_focus, "UShort", variation, "cdecl uint") - ; If more than 256 results, run the function with the true capacity. - if (count > capacity) { - result.size := A_PtrSize * count - count := DllCall(code, "ptr", result, "uint", capacity - , "ptr", this.ptr, "uint", this.width, "uint", this.height - , "ptr", image.ptr, "uint", image.width, "uint", image.height, "cdecl uint") - } + ; Prevent another search for focused pixel + image.coord_focus := NumGet(result, 2*4*count, "UInt") + coord_focus := image.coord_focus ; Check if any matches are found. if (count = 0) return False + ; If more than 256 results, run the function with the true capacity. + if (count > capacity) { + result.Size := 2 * 4 * count + 4 + count := DllCall(code, "ptr", result, "uint", count + , "ptr", this.ptr, "uint", this.width, "uint", this.height + , "ptr", image.ptr, "uint", image.width, "uint", image.height + , "UInt", coord_focus, "UShort", variation, "cdecl uint") + } + ; Create an array of [x, y] coordinates. xys := [] - xys.count := count loop count { - address := NumGet(result, A_PtrSize*(A_Index-1), "ptr") - offset := (address - this.ptr) // 4 - xy := [mod(offset, this.width), offset // this.width] + xy := [NumGet(result, 2*4*(A_Index-1), "UInt"), + NumGet(result, 2*4*(A_Index-1) + 4, "UInt")] xys.push(xy) } return xys diff --git a/source/imagesearch2.c b/source/imagesearch2.c new file mode 100644 index 00000000..25a6e239 --- /dev/null +++ b/source/imagesearch2.c @@ -0,0 +1,156 @@ +__attribute__((ms_abi)) // Tells GCC we want to compile for Windows. +__attribute__ ((target ("sse4.2"))) // According to godbolt.org it doesn't do anything even with + // __builtin_assume_aligned(ptr, 16) and -Ofast -msse4.2. + // You might want to study SIMD instructions and if there is a good instruction to + // take advantage of, go with inline assembly. +unsigned int imagesearch2(unsigned int * restrict result, unsigned int * start, unsigned int width, unsigned int height, unsigned int * s, unsigned int w, unsigned int h, unsigned int coord_focus, unsigned short variation) { + // width, height, start, current, end, color refer to the haystack (main image) + // x, y, w, h, s, c, e, cf refer to the needle (search image) + // The location of the focused pixel + unsigned short x; + unsigned short y; + + if ( coord_focus ) { + x = coord_focus >> sizeof(x)*8; + y = coord_focus & 0x0000ffff; + goto focus_determined; + } + + // Try to locate the focused pixel in the middle of the sprite + unsigned int * c = s + w/4 + h/4 * w; + unsigned int * last_pixel = s + w + h * w; + while(c < last_pixel) { + for (unsigned int * e = c + w / 2; c < e; c++) { + if ( *((unsigned char *) c + 3) ) { + unsigned int offset = (c - s); + x = offset % w; + y = offset / w; + goto focus_determined; + } + } + c += w / 2; + } + + // If every pixel in the middle was transparent + // try to find a non-transparent pixel on the left-hand side. + + // This falls into an infinite loop if somehow the sprite doesn't have any + // non-transparent pixel in the leftmost quarter. + if ( *((unsigned char *)(s + x + y * w) + 3) == 0 ) { + unsigned int * c = s + (w/4-1) + (h-1) * w; + while(-1) { + for (unsigned int * e = c - w / 4; c > e; c--) { + if ( *((unsigned char *) c + 3) ) { + unsigned int offset = (c - s); + x = offset % w; + y = offset / w; + goto focus_determined; + } + } + c -= w - w / 4; + } + } + + focus_determined:; + + // Hide the coordinates of the focused pixel + *(result + 2) = x << sizeof(x)*8 | y; + + + + // Prepare the search. + + // The color on the focused pixel + unsigned int cf = *(s + x + y * w); + + // We don't need to search in the narrow edge on the right-hand side + unsigned int range_width = width - w; + // Remaining area must be greater than search height + unsigned int range_height = height - h; + + unsigned int * current = start; + unsigned int * end = start + width * range_height; + + // Start the search. + unsigned int left = 0; + while ( current < end ) { + + unsigned int offset = current - start; + //unsigned int left = offset % width; + // TODO Remove the comment below + // I believe div is worse than cmov'ing one constant number. + // The code loses some readability though. + unsigned int top = offset / width; // optimized away + + // Checks before subimage loop. + + // X-Range Check + if ( left > range_width ) { + current += w - 1; + left = 0; + continue; + } + // + + // Focused Pixel + unsigned int * color; + color = current + x + y * width; + for (int b = 0; b < 3; b++) { + unsigned short diff = *((unsigned char *)&cf + b) - *((unsigned char *)color + b); + if ( diff > variation && diff < (unsigned short)(0 - variation) ) { + current++; + left++; + goto next; + } + } + + // Subimage loop. + unsigned int * c = s; + color = current; + for (int i = 0; i < h; i++) { + unsigned int * e = c + w; + while (c < e) { + if ( *((unsigned char *) c + 3) ) { // Skip transparent pixels + for (int b = 0; b < 3; b++) { + unsigned short diff = *((unsigned char *) c + b) - *((unsigned char *) color + b); + if ( diff > variation && diff < (unsigned short)(0 - variation) ) { + current++; + left++; + goto next; + } + } + } + c++; // Iterate over the needle image + color++; // Iterate over the haystack image + } + color = color - w + width; // Reset pointer for each scanline + } + + // Found a matching image! + *(result) = (current - start) % width; + *(result + 1) = (current - start) / width; + return 1; + + next: + if ( left >= width ) { + left = 0; + } + } + +// TODO Remove the comment below for clean code +// +// This is how I checked the input data, writing the first few pixels at s or start +// and then ImagePutClipboard and check each pixel's color in GIMP. +// +// It seems loading with ({sprite: fpath}) gives you the right buffer but +// loading with (fpath, transparent_color) gives a buffer with no transparent pixels +// even if the file had pixels with the matching transparent_color. +// +//for ( unsigned int k = 0; k < w*h/2; k++ ) { +// *(result+k) = *(s + k%32); +//} +//return (w*h)/2/2; +// + + return 0; +} \ No newline at end of file diff --git a/source/imagesearchall2.c b/source/imagesearchall2.c new file mode 100644 index 00000000..5185d16c --- /dev/null +++ b/source/imagesearchall2.c @@ -0,0 +1,164 @@ +__attribute__((ms_abi)) // Tells GCC we want to compile for Windows. +__attribute__ ((target ("sse4.2"))) // According to godbolt.org it doesn't do anything even with + // __builtin_assume_aligned(ptr, 16) and -Ofast -msse4.2. + // You might want to study SIMD instructions and if there is a good instruction to + // take advantage of, go with inline assembly. +unsigned int imagesearchall2(unsigned int * restrict result, unsigned int capacity, unsigned int * start, unsigned int width, unsigned int height, unsigned int * s, unsigned int w, unsigned int h, unsigned int coord_focus, unsigned short variation ) { + // width, height, start, current, end, color refer to the haystack (main image) + // x, y, w, h, s, c, e, cf refer to the needle (search image) + unsigned int count = 0; + + // The location of the focused pixel + unsigned short x; + unsigned short y; + + if ( coord_focus ) { + x = coord_focus >> sizeof(x)*8; + y = coord_focus & 0x0000ffff; + goto focus_determined; + } + + // Try to locate the focused pixel in the middle of the sprite + unsigned int * c = s + w/4 + h/4 * w; + unsigned int * last_pixel = s + w + h * w; + while(c < last_pixel) { + for (unsigned int * e = c + w / 2; c < e; c++) { + if ( *((unsigned char *) c + 3) ) { + unsigned int offset = (c - s); + x = offset % w; + y = offset / w; + goto focus_determined; + } + } + c += w / 2; + } + + // If every pixel in the middle was transparent + // try to find a non-transparent pixel on the left-hand side. + + // This falls into an infinite loop if somehow the sprite doesn't have any + // non-transparent pixel in the leftmost quarter. + if ( *((unsigned char *)(s + x + y * w) + 3) == 0 ) { + unsigned int * c = s + (w/4-1) + (h-1) * w; + while(-1) { + for (unsigned int * e = c - w / 4; c > e; c--) { + if ( *((unsigned char *) c + 3) ) { + unsigned int offset = (c - s); + x = offset % w; + y = offset / w; + goto focus_determined; + } + } + c -= w - w / 4; + } + } + + focus_determined:; + + + + // Prepare the search. + + // The color on the focused pixel + unsigned int cf = *(s + x + y * w); + + // We don't need to search in the narrow edge on the right-hand side + unsigned int range_width = width - w; + // Remaining area must be greater than search height + unsigned int range_height = height - h; + + unsigned int * current = start; + unsigned int * end = start + width * range_height; + + // Start the search. + unsigned int left = 0; + while ( current < end ) { + + unsigned int offset = current - start; + //unsigned int left = offset % width; + // TODO Remove the comment below + // I believe div is worse than cmov'ing one constant number. + // The code loses some readability though. + unsigned int top = offset / width; // optimized away + + // Checks before subimage loop. + + // X-Range Check + if ( left > range_width ) { + current += w - 1; + left = 0; + continue; + } + // + + // Focused Pixel + unsigned int * color; + color = current + x + y * width; + for (int b = 0; b < 3; b++) { + unsigned short diff = *((unsigned char *)&cf + b) - *((unsigned char *)color + b); + if ( diff > variation && diff < (unsigned short)(0 - variation) ) { + current++; + left++; + goto next; + } + } + + // Subimage loop. + unsigned int * c = s; + color = current; + for (int i = 0; i < h; i++) { + unsigned int * e = c + w; + while (c < e) { + if ( *((unsigned char *) c + 3) ) { // Skip transparent pixels + for (int b = 0; b < 3; b++) { + unsigned short diff = *((unsigned char *) c + b) - *((unsigned char *) color + b); + if ( diff > variation && diff < (unsigned short)(0 - variation) ) { + current++; + left++; + goto next; + } + } + } + c++; // Iterate over the needle image + color++; // Iterate over the haystack image + } + color = color - w + width; // Reset pointer for each scanline + } + + // Found a matching image! + if ( count < capacity ) { + *(result + count * 2) = (current - start) % width; + *(result + count * 2 + 1) = (current - start) / width; + } + count++; + + // XXX Let us not deal with overlapped matches + current += w; + left += w; + + next: + if ( left >= width ) { + left = 0; + } + } + + // Hide the coordinates of the focused pixel + *(result + count * 2) = x << sizeof(x)*8 | y; + +// TODO Remove the comment below for clean code +// +// This is how I checked the input data, writing the first few pixels at s or start +// and then ImagePutClipboard and check each pixel's color in GIMP. +// +// It seems loading with ({sprite: fpath}) gives you the right buffer but +// loading with (fpath, transparent_color) gives a buffer with no transparent pixels +// even if the file had pixels with the matching transparent_color. +// +//for ( unsigned int k = 0; k < w*h/2; k++ ) { +// *(result+k) = *(s + k%32); +//} +//return (w*h)/2/2; +// + + return count; +} \ No newline at end of file From 57cfafc6ffda44529499de078f064e2d7fe665ec Mon Sep 17 00:00:00 2001 From: "Gunwoo Gim (il debole)" Date: Thu, 14 Dec 2023 15:45:04 +0900 Subject: [PATCH 471/492] Update ImageSearch method of BitmapBuffer --- ImagePut.ahk | 57 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index e4152954..726896e8 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2838,10 +2838,10 @@ class ImagePut { return xys } - ImageSearch(image) { - ; FIXME Since I haven't install the GCC libraries for 32bit libraries and build 32bit binary, it won't work on 32-bit systems, Thank you for your understanding! + ImageSearch(image, variation := 0) { + ; FIXME Since I haven't installed the GCC libraries for 32bit libraries and build 32bit binary, it won't work on 32-bit systems, Thank you for your understanding! if ( A_PtrSize == 4 ) { - MsgBox("Since I haven't install the GCC libraries for 32bit libraries and build 32bit binary, it won't work on 32-bit systems, Thank you for your understanding!") + MsgBox("Since I haven't installed the GCC libraries for 32bit libraries and build 32bit binary, it won't work on 32-bit systems, Thank you for your understanding!") return False } @@ -2850,33 +2850,54 @@ class ImagePut { ? "VYnlV1ZTg+wgi0Uki1UYi30Ui00gD6/Qi3UIix8Pr0UMAcqJXeSLHJeLfQwByItVECtVHIlF7MHnAold4ItdDA+v1ytdGANVCIlV" . "3Ild2ItF3DnGc3CLReyLTeA5DIZ1YInwK0UIMdLB+AL3dQw5VdhyTotF5DkGdUeLRRgx0onxiVXwweACiUXoi0UUi13wO10cdDyL" . "VeiJywHCiVXUi1XUOdBzFIB4AwB0BosTORB1D4PABIPDBOvl/0XwAfnrzIPGBOuJi0UQD6/HA0UIicaDxCCJ8FteX13D" - : "QVdBVkFVQVRVV1ZTSIPsKIuEJKgAAACLnCSQAAAARYshQYnSicJJicuLjCSgAAAAD6/TRInXQQ+vwinfiXwkHEgBykWLLJFEicIr" - . "lCSYAAAASAHIQQ+v0kiJRCQITInZSY0sk0g56Q+DgAAAAEiLRCQIRDksgXVsSInIMdJMKdhIwfgCQffyOVQkHHJXRDkhdVKJ3jH/" - . "MdJIjQS1AAAAAEiJRCQQTInIO5QkmAAAAHRESIt0JBBBif5OjTSxTI08MEw5+HMXgHgDAHQHQYs2OTB1EUiDwARJg8YE6+T/wkQB" - . "1+vESIPBBOl3////RQ+vwkuNDINIichIg8QoW15fXUFcQV1BXkFfww==") + : "QVdBVkFVQVRVV1ZTSIPsOIuEJLgAAACLrCSwAAAARA+3lCTAAAAASImMJIAAAACLjCSoAAAASImUJIgAAABEiYQkkAAAAIXAD4Va" + . "AwAAiehBicxIi7wkoAAAAInKwegCQcHsAkiLnCSgAAAAD6/BRInmSAHwSI0Eh4nPD6/9QYn4TAHCTI0ck0w52A+DqwIAAEGJyEHR" + . "6EnB4AJKjRQASDnCdxnpHwMAAA8fgAAAAABIg8AESDnCD4ZzAgAAgHgDAHTtSCuEJKAAAAAx0kGJyEjB+AL38Q+32kGJ0w+30EQP" + . "r8KJ0EkB2EnB4AJBweMQQSnpSIu8JIgAAABEi7wkkAAAAEQPr4wkkAAAAEEJw0iLhCSAAAAAQSnPRIlYCEiLhCSgAAAATo00j0KL" + . "BABMOfcPg54BAAAPr5QkkAAAAEWJ00H320gB2kiLnCSIAAAASI08lQAAAACJykiNdwFIiXwkCEiDxwJMjSSVAAAAAEiJdCQQi7Qk" + . "kAAAAEiJfCQYD7b4SYn1Zol8JCQPtvzB6BBJKdWNUf9IiXQkKA+2wEiNNJUAAAAAiXwkIEnB5QJIiTQkMfZmiUQkJusTDx9AAEgD" + . "HCQx9kw58w+DBgEAAEQ5/nfsSItEJAgPthQDD7dEJCQp0GZBOcJzCmZEOdgPgsUAAABIi0QkEA+2FAMPt0QkICnQZkE5wnMKZkQ5" + . "2A+CpQAAAEiLRCQYD7YUAw+3RCQmKdBmQTnCcwpmRDnYD4KFAAAAhe0PhLIAAABIi4QkoAAAAEiJ2jH/To0EIEk5wHcb6ZcAAABm" + . "Dx+EAAAAAABIg8AESIPCBEk5wHZzgHgDAHTtD7YIRA+2CkQpyWZBOcpzBmZEOdlyMA+2SAFED7ZKAUQpyWZBOcpzBmZEOdlyGA+2" + . "SAJED7ZKAkQpyWZBOcpzrWZEOdlzp4PGATHASIPDBDu0JJAAAAAPQ/BMOfMPgvr+//8xwOtGDx+AAAAAAIPHAUwB6jnvD4Vb////" + . "SInYSCuEJIgAAABIwfgCSJlI93wkKGYPbsJmDzoiwAFIi4QkgAAAAGYP1gC4AQAAAEiDxDhbXl9dQVxBXUFeQV/DTAHASTnDD4df" + . "/f//TIu0JKAAAABFMcAx2zHASYnbicJDgHwGAwAPhZD9//9BichBjUQk/ynPRSngSAH4SI0UtQAAAABJweACSY0Ehkj32kn32EmJ" + . "w0kB03IP60QPH0AASIPoBEk5w3M3gHgDAHTx6R/9//8PH0AAD7fQicNBidDB6xCJ0EQPr8FBidtJAdhJweAC6ST9//9IidDpY///" + . "/0wBwOut") + ;: "QVdBVkFVQVRVV1ZTSIPsKIuEJKgAAACLnCSQAAAARYshQYnSicJJicuLjCSgAAAAD6/TRInXQQ+vwinfiXwkHEgBykWLLJFEicIr" + ;. "lCSYAAAASAHIQQ+v0kiJRCQITInZSY0sk0g56Q+DgAAAAEiLRCQIRDksgXVsSInIMdJMKdhIwfgCQffyOVQkHHJXRDkhdVKJ3jH/" + ;. "MdJIjQS1AAAAAEiJRCQQTInIO5QkmAAAAHRESIt0JBBBif5OjTSxTI08MEw5+HMXgHgDAHQHQYs2OTB1EUiDwARJg8YE6+T/wkQB" + ;. "1+vESIPBBOl3////RQ+vwkuNDINIichIg8QoW15fXUFcQV1BXkFfww==") ; Convert image to a buffer object. if !(IsObject(image) && ObjHasOwnProp(image, "ptr") && ObjHasOwnProp(image, "size")) image := ImagePutBuffer(image) - ; Search for the address of the first matching image. - address := DllCall(code, "ptr", this.ptr, "uint", this.width, "uint", this.height - , "ptr", image.ptr, "uint", image.width, "uint", image.height, "uint", image.width//2, "uint", image.height//2 - , "cdecl ptr") + ; Check if the object has the coordinates. + coord_focus := ObjHasOwnProp(image, "coord_focus") ? image.coord_focus : 0 - ; Compare the address to the out-of-bounds limit. - if (address == this.ptr + this.size) - return False + ; Search for the coordinates of the first matching image. + count := DllCall(code, "ptr", this.ptr, "uint", this.width, "uint", this.height + , "ptr", image.ptr, "uint", image.width, "uint", image.height, + , "UInt", coord_focus, "UShort", variation, "cdecl ptr") + + ; Prevent another search for focused pixel + image.coord_focus := NumGet(result, 4*2, "UInt") + coord_focus := image.coord_focus + + if (count = 0) + return false ; Return an [x, y] array. - offset := (address - this.ptr) // 4 - return [mod(offset, this.width), offset // this.width] + xy := [NumGet(result, 4*0, "UInt"), + NumGet(result, 4*1, "UInt")] + return xy; } ImageSearchAll(image, variation := 0) { - ; FIXME Since I haven't install the GCC libraries for 32bit libraries and build 32bit binary, it won't work on 32-bit systems, Thank you for your understanding! + ; FIXME Since I haven't installed the GCC libraries for 32bit libraries and build 32bit binary, it won't work on 32-bit systems, Thank you for your understanding! if ( A_PtrSize == 4 ) { - MsgBox("Since I haven't install the GCC libraries for 32bit libraries and build 32bit binary, it won't work on 32-bit systems, Thank you for your understanding!") + MsgBox("Since I haven't installed the GCC libraries for 32bit libraries and build 32bit binary, it won't work on 32-bit systems, Thank you for your understanding!") return False } From d3c883dcc4cdabb440dbcc58efe9246209880b32 Mon Sep 17 00:00:00 2001 From: "Gunwoo Gim (il debole)" Date: Thu, 14 Dec 2023 15:48:41 +0900 Subject: [PATCH 472/492] Remove an unnecessary assignment to a variable --- ImagePut.ahk | 1 - 1 file changed, 1 deletion(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index 726896e8..ac786277 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2883,7 +2883,6 @@ class ImagePut { ; Prevent another search for focused pixel image.coord_focus := NumGet(result, 4*2, "UInt") - coord_focus := image.coord_focus if (count = 0) return false From dd7e974ddd9ebc8d1b8df701bffb1d5a7a0f0171 Mon Sep 17 00:00:00 2001 From: "Gunwoo Gim (il debole)" Date: Thu, 14 Dec 2023 16:09:38 +0900 Subject: [PATCH 473/492] Recover the lost work on my wife's windows system --- ImagePut.ahk | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index ac786277..048a682f 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2877,9 +2877,11 @@ class ImagePut { coord_focus := ObjHasOwnProp(image, "coord_focus") ? image.coord_focus : 0 ; Search for the coordinates of the first matching image. - count := DllCall(code, "ptr", this.ptr, "uint", this.width, "uint", this.height - , "ptr", image.ptr, "uint", image.width, "uint", image.height, - , "UInt", coord_focus, "UShort", variation, "cdecl ptr") + result := Buffer(2 * 4 + 4) + count := DllCall(code, "ptr", result + , "ptr", this.ptr, "uint", this.width, "uint", this.height + , "ptr", image.ptr, "uint", image.width, "uint", image.height + , "UInt", coord_focus, "UShort", variation, "cdecl uint") ; Prevent another search for focused pixel image.coord_focus := NumGet(result, 4*2, "UInt") @@ -2890,7 +2892,7 @@ class ImagePut { ; Return an [x, y] array. xy := [NumGet(result, 4*0, "UInt"), NumGet(result, 4*1, "UInt")] - return xy; + return xy } ImageSearchAll(image, variation := 0) { From d834c70595c983d6a7027c5f3bb6cb942b043fbc Mon Sep 17 00:00:00 2001 From: "Gunwoo Gim (il debole)" Date: Thu, 14 Dec 2023 21:01:42 +0900 Subject: [PATCH 474/492] Accelerate when the argument variation is 0 --- source/imagesearch2.c | 28 ++++++++++++++++++++++------ source/imagesearchall2.c | 28 ++++++++++++++++++++++------ 2 files changed, 44 insertions(+), 12 deletions(-) diff --git a/source/imagesearch2.c b/source/imagesearch2.c index 25a6e239..ab18a0ca 100644 --- a/source/imagesearch2.c +++ b/source/imagesearch2.c @@ -95,13 +95,21 @@ unsigned int imagesearch2(unsigned int * restrict result, unsigned int * start, // Focused Pixel unsigned int * color; color = current + x + y * width; - for (int b = 0; b < 3; b++) { - unsigned short diff = *((unsigned char *)&cf + b) - *((unsigned char *)color + b); - if ( diff > variation && diff < (unsigned short)(0 - variation) ) { + if ( variation == 0 ) { + if ( cf != *color ) { current++; left++; goto next; } + } else { + for (int b = 0; b < 3; b++) { + unsigned short diff = *((unsigned char *)&cf + b) - *((unsigned char *)color + b); + if ( diff > variation && diff < (unsigned short)(0 - variation) ) { + current++; + left++; + goto next; + } + } } // Subimage loop. @@ -111,13 +119,21 @@ unsigned int imagesearch2(unsigned int * restrict result, unsigned int * start, unsigned int * e = c + w; while (c < e) { if ( *((unsigned char *) c + 3) ) { // Skip transparent pixels - for (int b = 0; b < 3; b++) { - unsigned short diff = *((unsigned char *) c + b) - *((unsigned char *) color + b); - if ( diff > variation && diff < (unsigned short)(0 - variation) ) { + if ( variation == 0 ) { + if ( *c != *color ) { current++; left++; goto next; } + } else { + for (int b = 0; b < 3; b++) { + unsigned short diff = *((unsigned char *) c + b) - *((unsigned char *) color + b); + if ( diff > variation && diff < (unsigned short)(0 - variation) ) { + current++; + left++; + goto next; + } + } } } c++; // Iterate over the needle image diff --git a/source/imagesearchall2.c b/source/imagesearchall2.c index 5185d16c..876d92bd 100644 --- a/source/imagesearchall2.c +++ b/source/imagesearchall2.c @@ -94,13 +94,21 @@ unsigned int imagesearchall2(unsigned int * restrict result, unsigned int capaci // Focused Pixel unsigned int * color; color = current + x + y * width; - for (int b = 0; b < 3; b++) { - unsigned short diff = *((unsigned char *)&cf + b) - *((unsigned char *)color + b); - if ( diff > variation && diff < (unsigned short)(0 - variation) ) { + if ( variation == 0 ) { + if ( cf != *color ) { current++; left++; goto next; } + } else { + for (int b = 0; b < 3; b++) { + unsigned short diff = *((unsigned char *)&cf + b) - *((unsigned char *)color + b); + if ( diff > variation && diff < (unsigned short)(0 - variation) ) { + current++; + left++; + goto next; + } + } } // Subimage loop. @@ -110,13 +118,21 @@ unsigned int imagesearchall2(unsigned int * restrict result, unsigned int capaci unsigned int * e = c + w; while (c < e) { if ( *((unsigned char *) c + 3) ) { // Skip transparent pixels - for (int b = 0; b < 3; b++) { - unsigned short diff = *((unsigned char *) c + b) - *((unsigned char *) color + b); - if ( diff > variation && diff < (unsigned short)(0 - variation) ) { + if ( variation == 0 ) { + if ( *c != *color ) { current++; left++; goto next; } + } else { + for (int b = 0; b < 3; b++) { + unsigned short diff = *((unsigned char *) c + b) - *((unsigned char *) color + b); + if ( diff > variation && diff < (unsigned short)(0 - variation) ) { + current++; + left++; + goto next; + } + } } } c++; // Iterate over the needle image From 05d7a47e38fa2567a91fae0f92b75c2c875b681a Mon Sep 17 00:00:00 2001 From: "Gunwoo Gim (il debole)" Date: Thu, 14 Dec 2023 21:07:27 +0900 Subject: [PATCH 475/492] Put back the carriage return characters on each line ending --- ImagePut.ahk | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index 048a682f..31ff6f4a 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2839,9 +2839,9 @@ class ImagePut { } ImageSearch(image, variation := 0) { - ; FIXME Since I haven't installed the GCC libraries for 32bit libraries and build 32bit binary, it won't work on 32-bit systems, Thank you for your understanding! + ; FIXME Since I haven't installed the GCC libraries for 32bit libraries and built 32bit binary, it won't work on 32-bit systems, Thank you for your understanding! if ( A_PtrSize == 4 ) { - MsgBox("Since I haven't installed the GCC libraries for 32bit libraries and build 32bit binary, it won't work on 32-bit systems, Thank you for your understanding!") + MsgBox("Since I haven't installed the GCC libraries for 32bit libraries and built 32bit binary, it won't work on 32-bit systems, Thank you for your understanding!") return False } @@ -2896,9 +2896,9 @@ class ImagePut { } ImageSearchAll(image, variation := 0) { - ; FIXME Since I haven't installed the GCC libraries for 32bit libraries and build 32bit binary, it won't work on 32-bit systems, Thank you for your understanding! + ; FIXME Since I haven't installed the GCC libraries for 32bit libraries and built 32bit binary, it won't work on 32-bit systems, Thank you for your understanding! if ( A_PtrSize == 4 ) { - MsgBox("Since I haven't installed the GCC libraries for 32bit libraries and build 32bit binary, it won't work on 32-bit systems, Thank you for your understanding!") + MsgBox("Since I haven't installed the GCC libraries for 32bit libraries and built 32bit binary, it won't work on 32-bit systems, Thank you for your understanding!") return False } From 8fd1cc08868b675b2eef7da0d3965bf8899969b8 Mon Sep 17 00:00:00 2001 From: "Gunwoo Gim (il debole)" Date: Thu, 14 Dec 2023 21:12:56 +0900 Subject: [PATCH 476/492] As you learn English, the quality of the comments improves --- source/imagesearch2.c | 2 +- source/imagesearchall2.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/imagesearch2.c b/source/imagesearch2.c index ab18a0ca..417eec37 100644 --- a/source/imagesearch2.c +++ b/source/imagesearch2.c @@ -53,7 +53,7 @@ unsigned int imagesearch2(unsigned int * restrict result, unsigned int * start, focus_determined:; - // Hide the coordinates of the focused pixel + // Stash the coordinates of the focused pixel *(result + 2) = x << sizeof(x)*8 | y; diff --git a/source/imagesearchall2.c b/source/imagesearchall2.c index 876d92bd..65708965 100644 --- a/source/imagesearchall2.c +++ b/source/imagesearchall2.c @@ -158,7 +158,7 @@ unsigned int imagesearchall2(unsigned int * restrict result, unsigned int capaci } } - // Hide the coordinates of the focused pixel + // Stash the coordinates of the focused pixel *(result + count * 2) = x << sizeof(x)*8 | y; // TODO Remove the comment below for clean code From 713c809eac26ec3900eefed6bf743610d6cdc823 Mon Sep 17 00:00:00 2001 From: "Gunwoo Gim (il debole)" Date: Thu, 14 Dec 2023 23:20:23 +0900 Subject: [PATCH 477/492] Fix a bug where random memory location will be touched in focus-determine --- source/imagesearch2.c | 22 ++++++++++------------ source/imagesearchall2.c | 20 +++++++++----------- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/source/imagesearch2.c b/source/imagesearch2.c index 417eec37..75b8b370 100644 --- a/source/imagesearch2.c +++ b/source/imagesearch2.c @@ -36,19 +36,17 @@ unsigned int imagesearch2(unsigned int * restrict result, unsigned int * start, // This falls into an infinite loop if somehow the sprite doesn't have any // non-transparent pixel in the leftmost quarter. - if ( *((unsigned char *)(s + x + y * w) + 3) == 0 ) { - unsigned int * c = s + (w/4-1) + (h-1) * w; - while(-1) { - for (unsigned int * e = c - w / 4; c > e; c--) { - if ( *((unsigned char *) c + 3) ) { - unsigned int offset = (c - s); - x = offset % w; - y = offset / w; - goto focus_determined; - } + c = s + (w/4-1) + (h-1) * w; + while(-1) { + for (unsigned int * e = c - w / 4; c > e; c--) { + if ( *((unsigned char *) c + 3) ) { + unsigned int offset = (c - s); + x = offset % w; + y = offset / w; + goto focus_determined; } - c -= w - w / 4; } + c -= w - w / 4; } focus_determined:; @@ -113,7 +111,7 @@ unsigned int imagesearch2(unsigned int * restrict result, unsigned int * start, } // Subimage loop. - unsigned int * c = s; + c = s; color = current; for (int i = 0; i < h; i++) { unsigned int * e = c + w; diff --git a/source/imagesearchall2.c b/source/imagesearchall2.c index 65708965..b483352b 100644 --- a/source/imagesearchall2.c +++ b/source/imagesearchall2.c @@ -38,19 +38,17 @@ unsigned int imagesearchall2(unsigned int * restrict result, unsigned int capaci // This falls into an infinite loop if somehow the sprite doesn't have any // non-transparent pixel in the leftmost quarter. - if ( *((unsigned char *)(s + x + y * w) + 3) == 0 ) { - unsigned int * c = s + (w/4-1) + (h-1) * w; - while(-1) { - for (unsigned int * e = c - w / 4; c > e; c--) { - if ( *((unsigned char *) c + 3) ) { - unsigned int offset = (c - s); - x = offset % w; - y = offset / w; - goto focus_determined; - } + c = s + (w/4-1) + (h-1) * w; + while(-1) { + for (unsigned int * e = c - w / 4; c > e; c--) { + if ( *((unsigned char *) c + 3) ) { + unsigned int offset = (c - s); + x = offset % w; + y = offset / w; + goto focus_determined; } - c -= w - w / 4; } + c -= w - w / 4; } focus_determined:; From 91a0e8283db599c1dd1c659c1abe612ebb9a9698 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 14 Dec 2023 17:30:02 -0500 Subject: [PATCH 478/492] Restore Default Behavior of ImageSearch --- ImagePut.ahk | 155 ++++++++++++++++++++++++------------------ source/imagesearch1.c | 57 +++++++++------- 2 files changed, 118 insertions(+), 94 deletions(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index 31ff6f4a..10353a0f 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2425,7 +2425,7 @@ class ImagePut { option := 7 else throw Error("Invalid variation parameter.") - ; ----------------------- Machine code generated with MCode4GCC using gcc 13.2.0 ----------------------- + ; ------------------------ Machine code generated with MCode4GCC using gcc 13.2.0 ------------------------ ; C source code - https://godbolt.org/z/zr71creqn pixelsearch1 := this.Base64Code((A_PtrSize == 4) @@ -2478,7 +2478,7 @@ class ImagePut { . "QTp0CQJy00E4fAgBcsxBOnwJAXLFQTgsCHK/QTosCXK56wNMidgPKDQkDyh8JBBEDyhEJCBEDyhMJDBEDyhUJEBIg8RQW15fXUFc" . "ww==") - ; ------------------------------------------------------------------------------------------------------ + ; -------------------------------------------------------------------------------------------------------- ; When doing pointer arithmetic, *Scan0 + 1 is actually adding 4 bytes. if (option == 1) @@ -2634,7 +2634,7 @@ class ImagePut { option := 7 else throw Error("Invalid variation parameter.") - ; ----------------------- Machine code generated with MCode4GCC using gcc 13.2.0 ----------------------- + ; ------------------------ Machine code generated with MCode4GCC using gcc 13.2.0 ------------------------ ; C source code - https://godbolt.org/z/GYMPYv4qT pixelsearchall1 := this.Base64Code((A_PtrSize == 4) @@ -2691,7 +2691,7 @@ class ImagePut { . "cj1BOmwJAnI2RThkCAFyL0U6ZAkBcihFOCwIciJFOiwJchxEO5QkyAAAAHMPSIu8JMAAAABFiddKiQT/Qf/C/0QkDEiDwQTrnw8o" . "dCQgDyh8JDBEidBEDyhEJEBEDyhMJFBEDyhUJGBIg8R4W15fXUFcQV1BXkFfww==") - ; ------------------------------------------------------------------------------------------------------ + ; -------------------------------------------------------------------------------------------------------- ; Global number of addresses (matching searches) to allocate. limit := 256 @@ -2839,17 +2839,31 @@ class ImagePut { } ImageSearch(image, variation := 0) { - ; FIXME Since I haven't installed the GCC libraries for 32bit libraries and built 32bit binary, it won't work on 32-bit systems, Thank you for your understanding! - if ( A_PtrSize == 4 ) { - MsgBox("Since I haven't installed the GCC libraries for 32bit libraries and built 32bit binary, it won't work on 32-bit systems, Thank you for your understanding!") - return False - } + + ; Convert image to a buffer object. + if !(IsObject(image) && ObjHasOwnProp(image, "ptr") && ObjHasOwnProp(image, "size")) + image := ImagePutBuffer(image) + + ; Check if the object has the coordinates. + x := ObjHasOwnProp(image, "x") ? image.x : image.width//2 + y := ObjHasOwnProp(image, "y") ? image.y : image.height//2 + + if (variation == 0) + option := 1 + else + option := 2 + + ; ------------------------ Machine code generated with MCode4GCC using gcc 13.2.0 ------------------------ ; C source code - https://godbolt.org/z/cKxrrT4ss - code := this.Base64Code((A_PtrSize == 4) + imagesearch1 := this.Base64Code((A_PtrSize == 4) ? "VYnlV1ZTg+wgi0Uki1UYi30Ui00gD6/Qi3UIix8Pr0UMAcqJXeSLHJeLfQwByItVECtVHIlF7MHnAold4ItdDA+v1ytdGANVCIlV" . "3Ild2ItF3DnGc3CLReyLTeA5DIZ1YInwK0UIMdLB+AL3dQw5VdhyTotF5DkGdUeLRRgx0onxiVXwweACiUXoi0UUi13wO10cdDyL" . "VeiJywHCiVXUi1XUOdBzFIB4AwB0BosTORB1D4PABIPDBOvl/0XwAfnrzIPGBOuJi0UQD6/HA0UIicaDxCCJ8FteX13D" + : "QVdBVkFVQVRVV1ZTSIPsGEWLIUSJw0SLhCSYAAAAQYnSi5QkkAAAAESJ1UiJzyusJIAAAABEicAPr4QkgAAAAEgB0EGLNIGJ2CuEJIgAAACDwAFBD6/CTI0cgUw52Q+DtAAAAEUPr8JJAdDrEA8fAEiDwQRMOdkPg5sAAABCOTSBde1Iicgx0kgp+EjB+AJB9/I51XLaRDkhddWLhCSIAAAAhcB0eouEJIAAAABFMfZFMf9IweACSIlEJAhMichMi2wkCESJ8kiNFJFJAcVMOehzTUSJdCQEDx+EAAAAAACAeAMAdAhEizJEOTB1gkiDwARIg8IETDnocuVEi3QkBEGDxwFEO7wkiAAAAHQSRQHW66wPH0QAAEEPr9pIjQyfSInISIPEGFteX11BXEFdQV5BX8M=") + + imagesearch2 := this.Base64Code((A_PtrSize == 4) + ? "" : "QVdBVkFVQVRVV1ZTSIPsOIuEJLgAAACLrCSwAAAARA+3lCTAAAAASImMJIAAAACLjCSoAAAASImUJIgAAABEiYQkkAAAAIXAD4Va" . "AwAAiehBicxIi7wkoAAAAInKwegCQcHsAkiLnCSgAAAAD6/BRInmSAHwSI0Eh4nPD6/9QYn4TAHCTI0ck0w52A+DqwIAAEGJyEHR" . "6EnB4AJKjRQASDnCdxnpHwMAAA8fgAAAAABIg8AESDnCD4ZzAgAAgHgDAHTtSCuEJKAAAAAx0kGJyEjB+AL38Q+32kGJ0w+30EQP" @@ -2864,49 +2878,59 @@ class ImagePut { . "/f//TIu0JKAAAABFMcAx2zHASYnbicJDgHwGAwAPhZD9//9BichBjUQk/ynPRSngSAH4SI0UtQAAAABJweACSY0Ehkj32kn32EmJ" . "w0kB03IP60QPH0AASIPoBEk5w3M3gHgDAHTx6R/9//8PH0AAD7fQicNBidDB6xCJ0EQPr8FBidtJAdhJweAC6ST9//9IidDpY///" . "/0wBwOut") - ;: "QVdBVkFVQVRVV1ZTSIPsKIuEJKgAAACLnCSQAAAARYshQYnSicJJicuLjCSgAAAAD6/TRInXQQ+vwinfiXwkHEgBykWLLJFEicIr" - ;. "lCSYAAAASAHIQQ+v0kiJRCQITInZSY0sk0g56Q+DgAAAAEiLRCQIRDksgXVsSInIMdJMKdhIwfgCQffyOVQkHHJXRDkhdVKJ3jH/" - ;. "MdJIjQS1AAAAAEiJRCQQTInIO5QkmAAAAHRESIt0JBBBif5OjTSxTI08MEw5+HMXgHgDAHQHQYs2OTB1EUiDwARJg8YE6+T/wkQB" - ;. "1+vESIPBBOl3////RQ+vwkuNDINIichIg8QoW15fXUFcQV1BXkFfww==") - ; Convert image to a buffer object. - if !(IsObject(image) && ObjHasOwnProp(image, "ptr") && ObjHasOwnProp(image, "size")) - image := ImagePutBuffer(image) + ; -------------------------------------------------------------------------------------------------------- - ; Check if the object has the coordinates. - coord_focus := ObjHasOwnProp(image, "coord_focus") ? image.coord_focus : 0 + ; Search for the address of the first matching image. + if (option == 1) + address := DllCall(imagesearch1, "ptr", this.ptr, "uint", this.width, "uint", this.height + , "ptr", image.ptr, "uint", image.width, "uint", image.height + , "uint", x, "uint", y, "cdecl ptr") ; Search for the coordinates of the first matching image. - result := Buffer(2 * 4 + 4) - count := DllCall(code, "ptr", result - , "ptr", this.ptr, "uint", this.width, "uint", this.height - , "ptr", image.ptr, "uint", image.width, "uint", image.height - , "UInt", coord_focus, "UShort", variation, "cdecl uint") - - ; Prevent another search for focused pixel - image.coord_focus := NumGet(result, 4*2, "UInt") + if (option == 2) + address := DllCall(imagesearch2, "ptr", this.ptr, "uint", this.width, "uint", this.height + , "ptr", image.ptr, "uint", image.width, "uint", image.height + , "uint", x, "uint", y, "ushort", variation, "cdecl ptr") - if (count = 0) - return false + ; Compare the address to the out-of-bounds limit. + if (address == this.ptr + this.size) + return False ; Return an [x, y] array. - xy := [NumGet(result, 4*0, "UInt"), - NumGet(result, 4*1, "UInt")] - return xy + offset := (address - this.ptr) // 4 + return [mod(offset, this.width), offset // this.width] } ImageSearchAll(image, variation := 0) { - ; FIXME Since I haven't installed the GCC libraries for 32bit libraries and built 32bit binary, it won't work on 32-bit systems, Thank you for your understanding! - if ( A_PtrSize == 4 ) { - MsgBox("Since I haven't installed the GCC libraries for 32bit libraries and built 32bit binary, it won't work on 32-bit systems, Thank you for your understanding!") - return False - } + + ; Convert image to a buffer object. + if !(IsObject(image) && ObjHasOwnProp(image, "ptr") && ObjHasOwnProp(image, "size")) + image := ImagePutBuffer(image) + + ; Check if the object has the coordinates. + x := ObjHasOwnProp(image, "x") ? image.x : image.width//2 + y := ObjHasOwnProp(image, "y") ? image.y : image.height//2 + + if (variation == 0) + option := 1 + else + option := 2 + + ; ------------------------ Machine code generated with MCode4GCC using gcc 13.2.0 ------------------------ ; C source code - https://godbolt.org/z/qPodGdP1d - code := this.Base64Code((A_PtrSize == 4) + imagesearchall1 := this.Base64Code((A_PtrSize == 4) ? "VYnlV1ZTg+wUi0UMi1UYi00IjTyFAAAAAItFECtFHA+vxwNFCIlF6ItFDCnQiUXkjQSVAAAAAIlF7ItF6DnBc2eLRRSLADkBdAmL" . "RRSAeAMAdVCJyCtFCDHSwfgC93UMOVXkfD4x0otFFInLiVXwi3XwO3UcdDyLVeyJ3gHCiVXgi1XgOdBzFIB4AwB0BosWORB1D4PA" . "BIPGBOvl/0XwAfvrzIPBBOuSi0UQD6/HA0UIicGDxBSJyFteX13D" + : "QVdBVkFVQVRVV1ZTSIPsGEUx20SLpCSYAAAAi4QkgAAAAESLlCSQAAAASIu8JIgAAABEKeBBD6/BSInLidZMicFNjSyARInIRCnQ" + . "iUQkDEqNBJUAAAAASIkEJEw56XN0iwc5AXQGgH8DAHViSInIMdJMKcBIwfgCQffxOVQkDHxNSIn4Me0x0kQ54nQyTIs8JEGJ7k6N" + . "NLFJAcdMOfhzGIB4AwB0CEWLFkQ5EHUgSIPABEmDxgTr4//CRAHN68lBOfNzB0SJ2EiJDMNB/8NIg8EE64dEidhIg8QYW15fXUFc" + . "QV1BXkFfww==") + + imagesearchall2 := this.Base64Code((A_PtrSize == 4) + ? "" : "QVdBVkFVQVRVV1ZTSIPsSIuEJNAAAACLtCTIAAAARImMJKgAAABED7eMJNgAAABIiYwkkAAAAImUJJgAAABMiYQkoAAAAIXAD4Xa" . "AwAARIuUJMAAAACJ8kSLnCTAAAAAweoCD6+UJMAAAACLjCTAAAAARA+v1kHB6wJIi7wkuAAAAESJ2EgBwkWJ0EiNFJdMAcFIjRyP" . "SDnaD4MOAwAARIuEJMAAAABB0ehJweACSo0MAkg50XcW6ZMDAAAPH0AASIPCBEg50Q+G1AIAAIB6AwB07UiJ0EgrhCS4AAAAMdJI" @@ -2922,49 +2946,44 @@ class ImagePut { . "AY0ECWYP1gSCg0QkLAFJAfsDnCTAAAAA6Uv///9MAcJIOdMPhwH9//9Ii7wkuAAAADHJRTHAMdJmRIlEJDCAfA8DAIlUJDQPhTv9" . "//+LjCTAAAAAQY1T/0QrlCTAAAAASMHgAkwB0kj32EQp2UiNFJdIweECSPfZSYnQSQHAchXrUWYuDx+EAAAAAABIg+oESTnQcz6A" . "egMAdPHpr/z//w8fQABBicBBwegQZkSJRCQw6br8///HRCQsAAAAAEiLtCSQAAAA6c/+//9IicrpTf///0gByuug") - ;: "QVdBVkFVQVRVV1ZTSIPsGEUx20SLpCSYAAAAi4QkgAAAAESLlCSQAAAASIu8JIgAAABEKeBBD6/BSInLidZMicFNjSyARInIRCnQ" - ;. "iUQkDEqNBJUAAAAASIkEJEw56XN0iwc5AXQGgH8DAHViSInIMdJMKcBIwfgCQffxOVQkDHxNSIn4Me0x0kQ54nQyTIs8JEGJ7k6N" - ;. "NLFJAcdMOfhzGIB4AwB0CEWLFkQ5EHUgSIPABEmDxgTr4//CRAHN68lBOfNzB0SJ2EiJDMNB/8NIg8EE64dEidhIg8QYW15fXUFc" - ;. "QV1BXkFfww==") - ; Convert image to a buffer object. - if !(IsObject(image) && ObjHasOwnProp(image, "ptr") && ObjHasOwnProp(image, "size")) - image := ImagePutBuffer(image) + ; -------------------------------------------------------------------------------------------------------- - ; Check if the object has the coordinates. - coord_focus := ObjHasOwnProp(image, "coord_focus") ? image.coord_focus : 0 + ; Global number of addresses (matching searches) to allocate. + limit := 256 + + ; If the limit is exceeded, the following routine will be run again. + redo: + result := Buffer(A_PtrSize * limit) ; Allocate buffer for addresses. ; Search for the address of the first matching image. - capacity := 256 - result := Buffer(2 * 4 * capacity + 4) - count := DllCall(code, "ptr", result, "uint", capacity - , "ptr", this.ptr, "uint", this.width, "uint", this.height - , "ptr", image.ptr, "uint", image.width, "uint", image.height - , "UInt", coord_focus, "UShort", variation, "cdecl uint") + count := DllCall(imagesearchall1, "ptr", result, "uint", limit + , "ptr", this.ptr, "uint", this.width, "uint", this.height + , "ptr", image.ptr, "uint", image.width, "uint", image.height + , "uint", x, "uint", y, "cdecl uint") - ; Prevent another search for focused pixel - image.coord_focus := NumGet(result, 2*4*count, "UInt") - coord_focus := image.coord_focus + count := DllCall(imagesearchall2, "ptr", result, "uint", limit + , "ptr", this.ptr, "uint", this.width, "uint", this.height + , "ptr", image.ptr, "uint", image.width, "uint", image.height + , "uint", x, "uint", y, "ushort", variation, "cdecl uint") + + ; If the default 256 results is exceeded, run the machine code again. + if (count > limit) { + limit := count + goto redo + } ; Check if any matches are found. if (count = 0) return False - ; If more than 256 results, run the function with the true capacity. - if (count > capacity) { - result.Size := 2 * 4 * count + 4 - count := DllCall(code, "ptr", result, "uint", count - , "ptr", this.ptr, "uint", this.width, "uint", this.height - , "ptr", image.ptr, "uint", image.width, "uint", image.height - , "UInt", coord_focus, "UShort", variation, "cdecl uint") - } - ; Create an array of [x, y] coordinates. xys := [] + xys.count := count loop count { - xy := [NumGet(result, 2*4*(A_Index-1), "UInt"), - NumGet(result, 2*4*(A_Index-1) + 4, "UInt")] - xys.push(xy) + address := NumGet(result, A_PtrSize * (A_Index-1), "ptr") + offset := (address - this.ptr) // 4 + xys.push([mod(offset, this.width), offset // this.width]) } return xys } diff --git a/source/imagesearch1.c b/source/imagesearch1.c index d2a628cc..cb9dd4b8 100644 --- a/source/imagesearch1.c +++ b/source/imagesearch1.c @@ -1,51 +1,56 @@ -unsigned int * imagesearch1(unsigned int * start, unsigned int width, unsigned int height, unsigned int * s, unsigned int w, unsigned int h) { +unsigned int * imagesearch1(unsigned int * start, unsigned int width, unsigned int height, unsigned int * s, unsigned int w, unsigned int h, unsigned int x, unsigned int y) { // width, height, start, current, end refer to the haystack (main image) // x, y, w, h, s, c, e refer to the needle (search image) + // Colors to be matched. + // c1 — c2 + // | | + // c3 — c4 + unsigned int c1 = *(s); + unsigned int c2 = *(s + x); + unsigned int c3 = *(s + y * w); + unsigned int c4 = *(s + x + y * w); + + // Search up to the first row of the remaining height. + unsigned int * end = start + width * (height - h + 1); // y_domain unsigned int * current = start; - unsigned int * end = start + width * (height - h); // Remaining area must be greater than search height - - int range_x = width - w; - int range_y = height - h; // optimized away - - int x, y, offset; - unsigned int * c; - unsigned int * e; - unsigned int * p; + unsigned int x_domain = width - w; // Start off searching with pointers. while (current < end) { - // Check if the current pixel matches the first pixel of subimage. - if (*current == *s || *((unsigned char *) s + 3) == 0) { // just continue if search image is transparent - - // Convert current pointer to (x, y). - offset = current - start; - x = offset % width; - y = offset / width; // optimized away + unsigned int offset = current - start; // Don't need to divide by 4 here. + unsigned int left = offset % width; + unsigned int top = offset / width; // optimized away - // Check if (x, y) exceeds bounds. - if (x > range_x) // range_y check is done above - goto next; + // Checks before subimage loop. + if (c4 == *(current + x + y * width) // Rank 1 - Focused Pixel + && (c1 == *(current)) // Rank 3 - First Pixel + && (left <= x_domain) // Rank 2 - X-Range Check (Note: Assembly says this is 2nd) + // && c2 == *(current + x) + // && c3 == *(current + y * width) + ) { // Subimage loop. - c = s; + unsigned int * c = s; for (int i = 0; i < h; i++) { - p = current + width * i; - e = c + w; + unsigned int * p = current + width * i; + unsigned int * e = c + w; while (c < e) { - if (*((unsigned char *) c + 3)) { // skip transparent pixels in search image + if (*((unsigned char *) c + 3)) { // Skip transparent pixels if (*c != *p) goto next; } - c++; // Here simply incrementing will interate the entire image - p++; // Will be reset each run + c++; // Iterate over the template image + p++; // Reset pointer for each scanline } } return current; } + next: current++; } + return start + width * height; // real end } \ No newline at end of file From 49769032939b7259c45f8f73c10d737e336ef3a8 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Thu, 14 Dec 2023 18:23:13 -0500 Subject: [PATCH 479/492] Fix ImageSearch2 --- ImagePut.ahk | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index 10353a0f..595b6bd0 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2838,7 +2838,7 @@ class ImagePut { return xys } - ImageSearch(image, variation := 0) { + ImageSearch(image, variation := 0, option := "") { ; Convert image to a buffer object. if !(IsObject(image) && ObjHasOwnProp(image, "ptr") && ObjHasOwnProp(image, "size")) @@ -2848,36 +2848,26 @@ class ImagePut { x := ObjHasOwnProp(image, "x") ? image.x : image.width//2 y := ObjHasOwnProp(image, "y") ? image.y : image.height//2 - if (variation == 0) - option := 1 - else - option := 2 + if (option == "") { + if (variation == 0) + option := 1 + else + option := 2 + } ; ------------------------ Machine code generated with MCode4GCC using gcc 13.2.0 ------------------------ - ; C source code - https://godbolt.org/z/cKxrrT4ss + ; C source code - https://godbolt.org/z/ej3YEWjfc imagesearch1 := this.Base64Code((A_PtrSize == 4) ? "VYnlV1ZTg+wgi0Uki1UYi30Ui00gD6/Qi3UIix8Pr0UMAcqJXeSLHJeLfQwByItVECtVHIlF7MHnAold4ItdDA+v1ytdGANVCIlV" . "3Ild2ItF3DnGc3CLReyLTeA5DIZ1YInwK0UIMdLB+AL3dQw5VdhyTotF5DkGdUeLRRgx0onxiVXwweACiUXoi0UUi13wO10cdDyL" . "VeiJywHCiVXUi1XUOdBzFIB4AwB0BosTORB1D4PABIPDBOvl/0XwAfnrzIPGBOuJi0UQD6/HA0UIicaDxCCJ8FteX13D" : "QVdBVkFVQVRVV1ZTSIPsGEWLIUSJw0SLhCSYAAAAQYnSi5QkkAAAAESJ1UiJzyusJIAAAABEicAPr4QkgAAAAEgB0EGLNIGJ2CuEJIgAAACDwAFBD6/CTI0cgUw52Q+DtAAAAEUPr8JJAdDrEA8fAEiDwQRMOdkPg5sAAABCOTSBde1Iicgx0kgp+EjB+AJB9/I51XLaRDkhddWLhCSIAAAAhcB0eouEJIAAAABFMfZFMf9IweACSIlEJAhMichMi2wkCESJ8kiNFJFJAcVMOehzTUSJdCQEDx+EAAAAAACAeAMAdAhEizJEOTB1gkiDwARIg8IETDnocuVEi3QkBEGDxwFEO7wkiAAAAHQSRQHW66wPH0QAAEEPr9pIjQyfSInISIPEGFteX11BXEFdQV5BX8M=") + ; C source code - https://godbolt.org/z/qGexdGqMn imagesearch2 := this.Base64Code((A_PtrSize == 4) ? "" - : "QVdBVkFVQVRVV1ZTSIPsOIuEJLgAAACLrCSwAAAARA+3lCTAAAAASImMJIAAAACLjCSoAAAASImUJIgAAABEiYQkkAAAAIXAD4Va" - . "AwAAiehBicxIi7wkoAAAAInKwegCQcHsAkiLnCSgAAAAD6/BRInmSAHwSI0Eh4nPD6/9QYn4TAHCTI0ck0w52A+DqwIAAEGJyEHR" - . "6EnB4AJKjRQASDnCdxnpHwMAAA8fgAAAAABIg8AESDnCD4ZzAgAAgHgDAHTtSCuEJKAAAAAx0kGJyEjB+AL38Q+32kGJ0w+30EQP" - . "r8KJ0EkB2EnB4AJBweMQQSnpSIu8JIgAAABEi7wkkAAAAEQPr4wkkAAAAEEJw0iLhCSAAAAAQSnPRIlYCEiLhCSgAAAATo00j0KL" - . "BABMOfcPg54BAAAPr5QkkAAAAEWJ00H320gB2kiLnCSIAAAASI08lQAAAACJykiNdwFIiXwkCEiDxwJMjSSVAAAAAEiJdCQQi7Qk" - . "kAAAAEiJfCQYD7b4SYn1Zol8JCQPtvzB6BBJKdWNUf9IiXQkKA+2wEiNNJUAAAAAiXwkIEnB5QJIiTQkMfZmiUQkJusTDx9AAEgD" - . "HCQx9kw58w+DBgEAAEQ5/nfsSItEJAgPthQDD7dEJCQp0GZBOcJzCmZEOdgPgsUAAABIi0QkEA+2FAMPt0QkICnQZkE5wnMKZkQ5" - . "2A+CpQAAAEiLRCQYD7YUAw+3RCQmKdBmQTnCcwpmRDnYD4KFAAAAhe0PhLIAAABIi4QkoAAAAEiJ2jH/To0EIEk5wHcb6ZcAAABm" - . "Dx+EAAAAAABIg8AESIPCBEk5wHZzgHgDAHTtD7YIRA+2CkQpyWZBOcpzBmZEOdlyMA+2SAFED7ZKAUQpyWZBOcpzBmZEOdlyGA+2" - . "SAJED7ZKAkQpyWZBOcpzrWZEOdlzp4PGATHASIPDBDu0JJAAAAAPQ/BMOfMPgvr+//8xwOtGDx+AAAAAAIPHAUwB6jnvD4Vb////" - . "SInYSCuEJIgAAABIwfgCSJlI93wkKGYPbsJmDzoiwAFIi4QkgAAAAGYP1gC4AQAAAEiDxDhbXl9dQVxBXUFeQV/DTAHASTnDD4df" - . "/f//TIu0JKAAAABFMcAx2zHASYnbicJDgHwGAwAPhZD9//9BichBjUQk/ynPRSngSAH4SI0UtQAAAABJweACSY0Ehkj32kn32EmJ" - . "w0kB03IP60QPH0AASIPoBEk5w3M3gHgDAHTx6R/9//8PH0AAD7fQicNBidDB6xCJ0EQPr8FBidtJAdhJweAC6ST9//9IidDpY///" - . "/0wBwOut") + : "QVdBVkFVQVRVV1ZTSIPsOESLnCSgAAAAi7wkqAAAAEGJ1EmJyouUJLgAAACLjCSwAAAAQSn4TImMJJgAAABIi7QkmAAAAEQPt4wkwAAAAInQRQ+vxEEPr8NPjTSCSAHIiwSGRInmRCneiXQkLE058g+DcAEAAEEPr9QPtthEieVmiVwkKA+23MHoEA+2wIlcJBxIAcpmiUQkKkiNDJUAAAAARInaSI1xAUgp1UyNLJUAAAAASIl0JBBBjVP/SI1xAkWJy0iJdCQgSMHlAjH2QffbTI08lQAAAABmDx9EAABBD7YUCg+3RCQoKdBmQTnBcwpmRDnYD4LTAAAASItEJBBBD7YUAg+3RCQcKdBmQTnBcwpmRDnYD4KyAAAASItEJCBBD7YUAg+3RCQqKdBmQTnBcwpmRDnYD4KRAAAAhf8PhKMAAABIi4QkmAAAAEyJfCQITInSMdtJic9OjQQoTDnAD4OBAAAAiVwkGOsTZpBIg8AESIPCBEw5wA+DfwAAAIB4AwB06Q+2CA+2GinZZkE5yXMGZkQ52XIsD7ZIAQ+2WgEp2WZBOclzBmZEOdlyFg+2SAIPtloCKdlmQTnJc69mRDnZc6lMiflMi3wkCIPGAUmDwgREOeZyPTH2TTnyD4L6/v//RTHSTInQSIPEOFteX11BXEFdQV5BX8MPHwCLXCQYSAHqg8MBOfsPhUn////r1Q8fQABNOfJzyTl0JCwPg7n+//9NAfpNOfJztzH26ar+//8=") ; -------------------------------------------------------------------------------------------------------- From b9f6e1938483dc7c77975876024a2227611bb363 Mon Sep 17 00:00:00 2001 From: "Gunwoo Gim (il debole)" Date: Sat, 16 Dec 2023 12:30:21 +0900 Subject: [PATCH 480/492] Fix bug where focus search loop could go out of range --- source/imagesearch2.c | 2 +- source/imagesearchall2.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/imagesearch2.c b/source/imagesearch2.c index 75b8b370..30d66de2 100644 --- a/source/imagesearch2.c +++ b/source/imagesearch2.c @@ -18,7 +18,7 @@ unsigned int imagesearch2(unsigned int * restrict result, unsigned int * start, // Try to locate the focused pixel in the middle of the sprite unsigned int * c = s + w/4 + h/4 * w; - unsigned int * last_pixel = s + w + h * w; + unsigned int * last_pixel = s + h * w; while(c < last_pixel) { for (unsigned int * e = c + w / 2; c < e; c++) { if ( *((unsigned char *) c + 3) ) { diff --git a/source/imagesearchall2.c b/source/imagesearchall2.c index b483352b..4111d01c 100644 --- a/source/imagesearchall2.c +++ b/source/imagesearchall2.c @@ -20,7 +20,7 @@ unsigned int imagesearchall2(unsigned int * restrict result, unsigned int capaci // Try to locate the focused pixel in the middle of the sprite unsigned int * c = s + w/4 + h/4 * w; - unsigned int * last_pixel = s + w + h * w; + unsigned int * last_pixel = s + h * w; while(c < last_pixel) { for (unsigned int * e = c + w / 2; c < e; c++) { if ( *((unsigned char *) c + 3) ) { From 4161cc1473f957eda4bdb891049e5c310997e899 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 15 Dec 2023 22:32:11 -0500 Subject: [PATCH 481/492] Add files via upload Finalize ImageSearch1 code to be efficient and bug-free. Supports transparency properly. Fast! --- source/__Note__.txt | 11 +++++++- source/imagesearch1.c | 63 ++++++++++++++++++++++--------------------- 2 files changed, 42 insertions(+), 32 deletions(-) diff --git a/source/__Note__.txt b/source/__Note__.txt index 53351ad0..734987f2 100644 --- a/source/__Note__.txt +++ b/source/__Note__.txt @@ -1,3 +1,12 @@ Use this at the top of your code to get the x64 calling convention -__attribute__((ms_abi)) // Tells GCC we want to compile for Windows. \ No newline at end of file +__attribute__((ms_abi)) // Tells GCC we want to compile for Windows. + + +The following regex is useful for formatting machine code: + +^(?:(?:1|2),x(?:86|64):)?(.{0,100})(.{0,100})(.{0,100})(.{0,100})(.{0,100})(.{0,100})(.{0,100})(.{0,100})(.{0,100})(?<10>.{0,100})(?<11>.{0,100})(?<12>.{0,100})$ + +"$1"`r`n. "$2"`r`n. "$3"`r`n. "$4"`r`n. "$5"`r`n. "$6"`r`n. "$7"`r`n. "$8"`r`n. "$9"`r`n. "${10}"`r`n. "${11}"`r`n. "${12}" + +Make sure to press #!v to paste it! \ No newline at end of file diff --git a/source/imagesearch1.c b/source/imagesearch1.c index cb9dd4b8..5dbd6887 100644 --- a/source/imagesearch1.c +++ b/source/imagesearch1.c @@ -1,46 +1,47 @@ unsigned int * imagesearch1(unsigned int * start, unsigned int width, unsigned int height, unsigned int * s, unsigned int w, unsigned int h, unsigned int x, unsigned int y) { - // width, height, start, current, end refer to the haystack (main image) - // x, y, w, h, s, c, e refer to the needle (search image) - - // Colors to be matched. - // c1 — c2 - // | | - // c3 — c4 - unsigned int c1 = *(s); - unsigned int c2 = *(s + x); - unsigned int c3 = *(s + y * w); - unsigned int c4 = *(s + x + y * w); - - // Search up to the first row of the remaining height. - unsigned int * end = start + width * (height - h + 1); // y_domain + // source: left, top, width, height, start, current, end refer to the haystack (main image) + // target: x, y, w, h, s, c, e refer to the needle (search or template image) + + int trans = (*((unsigned char *) s + 3) == 0); // Check if top-left pixel is transparent + + unsigned int c1 = *(s); // ↓ Top-left pixel + unsigned int c2 = *(s + x); // c1 — c2 + unsigned int c3 = *(s + y * w); // | | + unsigned int c4 = *(s + x + y * w); // c3 — c4 ← Focused pixel + + unsigned int x_domain = width - w; // Avoid search of the narrow edge on the right-hand side + unsigned int y_domain = height - h + 1; // Add 1 to search at least one row + + unsigned int * end = start + width * y_domain; // Remaining area must be greater than search height unsigned int * current = start; - unsigned int x_domain = width - w; // Start off searching with pointers. while (current < end) { - unsigned int offset = current - start; // Don't need to divide by 4 here. - unsigned int left = offset % width; - unsigned int top = offset / width; // optimized away - - // Checks before subimage loop. - if (c4 == *(current + x + y * width) // Rank 1 - Focused Pixel - && (c1 == *(current)) // Rank 3 - First Pixel - && (left <= x_domain) // Rank 2 - X-Range Check (Note: Assembly says this is 2nd) - // && c2 == *(current + x) - // && c3 == *(current + y * width) - ) { - - // Subimage loop. + unsigned int offset = current - start; // Don't need to divide by 4 here. + unsigned int left = offset % width; // Get x coordinate of source image + unsigned int top = offset / width; // optimized away + + // Rank Reasoning + // 1. The focused pixel has the most entropy and is least likely to match the source. + // CANNOT BE TRANSPARENT. + // 2. The top-left pixel may match the source. + // 3. The x-domain check determines if the match is too far to the right. + // Advancing the pointer by w - 1 makes little difference. + if (c4 == *(current + x + y * width)) // Rank 1 - Focused Pixel + if (trans || c1 == *(current)) // Rank 2 - Top-left Pixel + if (left <= x_domain) // Rank 3 - X-Domain Check + { + // Subimage matching loop. unsigned int * c = s; for (int i = 0; i < h; i++) { unsigned int * p = current + width * i; unsigned int * e = c + w; - while (c < e) { - if (*((unsigned char *) c + 3)) { // Skip transparent pixels + while (c < e) { // Scan line-by-line + if (*((unsigned char *) c + 3)) // Skip transparent pixels if (*c != *p) goto next; - } + c++; // Iterate over the template image p++; // Reset pointer for each scanline } From 365f9fad8e88a93655f8bcce0aa7082f0da18df7 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 15 Dec 2023 22:34:23 -0500 Subject: [PATCH 482/492] C source files --- source/imagesearch1.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/imagesearch1.c b/source/imagesearch1.c index 5dbd6887..8047ec08 100644 --- a/source/imagesearch1.c +++ b/source/imagesearch1.c @@ -1,5 +1,5 @@ unsigned int * imagesearch1(unsigned int * start, unsigned int width, unsigned int height, unsigned int * s, unsigned int w, unsigned int h, unsigned int x, unsigned int y) { - // source: left, top, width, height, start, current, end refer to the haystack (main image) + // source: left, top, width, height, start, current, end refer to the haystack (main image) // target: x, y, w, h, s, c, e refer to the needle (search or template image) int trans = (*((unsigned char *) s + 3) == 0); // Check if top-left pixel is transparent @@ -8,7 +8,7 @@ unsigned int * imagesearch1(unsigned int * start, unsigned int width, unsigned i unsigned int c2 = *(s + x); // c1 — c2 unsigned int c3 = *(s + y * w); // | | unsigned int c4 = *(s + x + y * w); // c3 — c4 ← Focused pixel - + unsigned int x_domain = width - w; // Avoid search of the narrow edge on the right-hand side unsigned int y_domain = height - h + 1; // Add 1 to search at least one row From d4e95cf73aafb837cfe28e441a78f15ca068f486 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 15 Dec 2023 22:44:53 -0500 Subject: [PATCH 483/492] C source files From 91c4d4b904ddb72c820833759c8a63bbadb75f43 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 15 Dec 2023 22:52:15 -0500 Subject: [PATCH 484/492] C source files Rename pack to iter --- source/pixelsearchall1x.c | 10 +++++----- source/pixelsearchall2x.c | 10 +++++----- source/pixelsearchall3x.c | 8 ++++---- source/pixelsearchall4x.c | 10 +++++----- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/source/pixelsearchall1x.c b/source/pixelsearchall1x.c index 57addb51..39ca3779 100644 --- a/source/pixelsearchall1x.c +++ b/source/pixelsearchall1x.c @@ -2,8 +2,8 @@ unsigned int pixelsearchall1x(unsigned int ** result, unsigned int limit, unsigned int * start, unsigned int * end, unsigned int color) { - // Number of 32-bit integers the register can hold. - int pack = 4; + // Number of 32-bit integers the register can iterate over. + int iter = 4; // Track number of matching searches. unsigned int count = 0; @@ -34,16 +34,16 @@ unsigned int pixelsearchall1x(unsigned int ** result, unsigned int limit, unsign // Clean up any remaining elements. while (start < end) { - if (pack > 0) { + if (iter > 0) { if (*start == color) { if (count < limit) *(result + count) = start; count++; } - pack--; + iter--; } else { - pack = 4; + iter = 4; goto loop; } start++; diff --git a/source/pixelsearchall2x.c b/source/pixelsearchall2x.c index 4cef244c..35627ae0 100644 --- a/source/pixelsearchall2x.c +++ b/source/pixelsearchall2x.c @@ -7,8 +7,8 @@ unsigned int pixelsearchall2x(unsigned int ** result, unsigned int limit, unsigned int * start, unsigned int * end, unsigned char rh, unsigned char rl, unsigned char gh, unsigned char gl, unsigned char bh, unsigned char bl) { - // Number of 32-bit integers the register can hold. - int pack = 4; + // Number of 32-bit integers the register can iterate over. + int iter = 4; // Track number of matching searches. unsigned int count = 0; @@ -51,7 +51,7 @@ unsigned int pixelsearchall2x(unsigned int ** result, unsigned int limit, unsign // Clean up any remaining elements. unsigned char r, g, b; while (start < end) { - if (pack > 0) { + if (iter > 0) { r = *((unsigned char *) start + 2); g = *((unsigned char *) start + 1); b = *((unsigned char *) start + 0); @@ -60,10 +60,10 @@ unsigned int pixelsearchall2x(unsigned int ** result, unsigned int limit, unsign *(result + count) = start; count++; } - pack--; + iter--; } else { - pack = 4; + iter = 4; goto loop; } start++; diff --git a/source/pixelsearchall3x.c b/source/pixelsearchall3x.c index acdef36b..87c53bbd 100644 --- a/source/pixelsearchall3x.c +++ b/source/pixelsearchall3x.c @@ -3,7 +3,7 @@ unsigned int pixelsearchall3x(unsigned int ** result, unsigned int limit, unsigned int * start, unsigned int * end, unsigned int * colors, unsigned int length) { // Number of 32-bit integers the register can hold. - int pack = 4; + int iter = 4; // Track number of matching searches. unsigned int count = 0; @@ -97,17 +97,17 @@ unsigned int pixelsearchall3x(unsigned int ** result, unsigned int limit, unsign // Clean up any remaining elements. exit: while (start < end) { - if (pack > 0) { + if (iter > 0) { for (int j = 0; j < check; j++) if (*start == colors[i + j]) { if (count < limit) *(result + count) = start; count++; } - pack--; + iter--; } else { - pack = 4; + iter = 4; goto loop; } start++; diff --git a/source/pixelsearchall4x.c b/source/pixelsearchall4x.c index db28bc48..248551ad 100644 --- a/source/pixelsearchall4x.c +++ b/source/pixelsearchall4x.c @@ -7,8 +7,8 @@ unsigned int pixelsearchall4x(unsigned int ** result, unsigned int limit, unsigned int * start, unsigned int * end, unsigned int * high, unsigned int * low, unsigned int length) { - // Number of 32-bit integers the register can hold. - int pack = 4; + // Number of 32-bit integers the register can iterate over. + int iter = 4; // Track number of matching searches. unsigned int count = 0; @@ -136,7 +136,7 @@ unsigned int pixelsearchall4x(unsigned int ** result, unsigned int limit, unsign exit: unsigned char r, g, b, rh, gh, bh, rl, gl, bl; while (start < end) { - if (pack > 0) { + if (iter > 0) { r = *((unsigned char *) start + 2); g = *((unsigned char *) start + 1); b = *((unsigned char *) start + 0); @@ -156,10 +156,10 @@ unsigned int pixelsearchall4x(unsigned int ** result, unsigned int limit, unsign count++; } } - pack--; + iter--; } else { - pack = 4; + iter = 4; goto loop; } start++; From 714e15a0226c491c8f765115a5f9449d9349ec79 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 15 Dec 2023 22:53:45 -0500 Subject: [PATCH 485/492] C source files Fix comment for pixelsearchall3 --- source/pixelsearchall3x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/pixelsearchall3x.c b/source/pixelsearchall3x.c index 87c53bbd..ee7703bb 100644 --- a/source/pixelsearchall3x.c +++ b/source/pixelsearchall3x.c @@ -2,7 +2,7 @@ unsigned int pixelsearchall3x(unsigned int ** result, unsigned int limit, unsigned int * start, unsigned int * end, unsigned int * colors, unsigned int length) { - // Number of 32-bit integers the register can hold. + // Number of 32-bit integers the register can iterate over. int iter = 4; // Track number of matching searches. From f20168f2fbe0a546219a4366459a07afb2d6a0cd Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Fri, 15 Dec 2023 23:01:45 -0500 Subject: [PATCH 486/492] Finalize ImageSearch1 --- ImagePut.ahk | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/ImagePut.ahk b/ImagePut.ahk index 595b6bd0..d2c7f9d5 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -2856,19 +2856,23 @@ class ImagePut { } ; ------------------------ Machine code generated with MCode4GCC using gcc 13.2.0 ------------------------ - - ; C source code - https://godbolt.org/z/ej3YEWjfc + ; C source code - https://godbolt.org/z/zGhb3dYcs imagesearch1 := this.Base64Code((A_PtrSize == 4) - ? "VYnlV1ZTg+wgi0Uki1UYi30Ui00gD6/Qi3UIix8Pr0UMAcqJXeSLHJeLfQwByItVECtVHIlF7MHnAold4ItdDA+v1ytdGANVCIlV" - . "3Ild2ItF3DnGc3CLReyLTeA5DIZ1YInwK0UIMdLB+AL3dQw5VdhyTotF5DkGdUeLRRgx0onxiVXwweACiUXoi0UUi13wO10cdDyL" - . "VeiJywHCiVXUi1XUOdBzFIB4AwB0BosTORB1D4PABIPDBOvl/0XwAfnrzIPGBOuJi0UQD6/HA0UIicaDxCCJ8FteX13D" - : "QVdBVkFVQVRVV1ZTSIPsGEWLIUSJw0SLhCSYAAAAQYnSi5QkkAAAAESJ1UiJzyusJIAAAABEicAPr4QkgAAAAEgB0EGLNIGJ2CuEJIgAAACDwAFBD6/CTI0cgUw52Q+DtAAAAEUPr8JJAdDrEA8fAEiDwQRMOdkPg5sAAABCOTSBde1Iicgx0kgp+EjB+AJB9/I51XLaRDkhddWLhCSIAAAAhcB0eouEJIAAAABFMfZFMf9IweACSIlEJAhMichMi2wkCESJ8kiNFJFJAcVMOehzTUSJdCQEDx+EAAAAAACAeAMAdAhEizJEOTB1gkiDwARIg8IETDnocuVEi3QkBEGDxwFEO7wkiAAAAHQSRQHW66wPH0QAAEEPr9pIjQyfSInISIPEGFteX11BXEFdQV5BX8M=") + ? "" + : "QVdBVkFVQVRVV1ZTSIPsGESLlCSYAAAARQ+2YQNEidAPr4QkgAAAAInTi5QkkAAAAESJxUiJz0GJ3UWLAUQrrCSAAAAASAHQQYs0" + . "gYnoK4QkiAAAAIPAAQ+vw0yNHIFMOdkPgwQBAABED6/TiWwkcEkB0usQDx8ASIPBBEw52Q+D4wAAAEI5NJF17UWE5A+FrAAAAEiJ" + . "yDHSSCn4SMH4AvfzQTnVctGLhCSIAAAAhcB0eIuEJIAAAABFMfZEiGQkD0Ux/0SJ8kiNLIUAAAAATInISI0UkUyNJChMOeBzS0iJ" + . "LCQPH0QAAIB4AwB0CosqOSgPhYAAAABIg8AESIPCBEw54HLjSIssJEGDxwFEObwkiAAAAHQTQQHeTI0kKESJ8kiNFJFMOeBytUiJ" + . "yEiDxBhbXl9dQVxBXUFeQV/DZpBEOQEPhEv///9Ig8EETDnZcxZCOTSRdOhIg8EETDnZD4Ig////Dx8Ai2wkcA+v3UiNDJ/rtQ8f" + . "AEQPtmQkD+n1/v//") ; C source code - https://godbolt.org/z/qGexdGqMn imagesearch2 := this.Base64Code((A_PtrSize == 4) ? "" : "QVdBVkFVQVRVV1ZTSIPsOESLnCSgAAAAi7wkqAAAAEGJ1EmJyouUJLgAAACLjCSwAAAAQSn4TImMJJgAAABIi7QkmAAAAEQPt4wkwAAAAInQRQ+vxEEPr8NPjTSCSAHIiwSGRInmRCneiXQkLE058g+DcAEAAEEPr9QPtthEieVmiVwkKA+23MHoEA+2wIlcJBxIAcpmiUQkKkiNDJUAAAAARInaSI1xAUgp1UyNLJUAAAAASIl0JBBBjVP/SI1xAkWJy0iJdCQgSMHlAjH2QffbTI08lQAAAABmDx9EAABBD7YUCg+3RCQoKdBmQTnBcwpmRDnYD4LTAAAASItEJBBBD7YUAg+3RCQcKdBmQTnBcwpmRDnYD4KyAAAASItEJCBBD7YUAg+3RCQqKdBmQTnBcwpmRDnYD4KRAAAAhf8PhKMAAABIi4QkmAAAAEyJfCQITInSMdtJic9OjQQoTDnAD4OBAAAAiVwkGOsTZpBIg8AESIPCBEw5wA+DfwAAAIB4AwB06Q+2CA+2GinZZkE5yXMGZkQ52XIsD7ZIAQ+2WgEp2WZBOclzBmZEOdlyFg+2SAIPtloCKdlmQTnJc69mRDnZc6lMiflMi3wkCIPGAUmDwgREOeZyPTH2TTnyD4L6/v//RTHSTInQSIPEOFteX11BXEFdQV5BX8MPHwCLXCQYSAHqg8MBOfsPhUn////r1Q8fQABNOfJzyTl0JCwPg7n+//9NAfpNOfJztzH26ar+//8=") + + ; -------------------------------------------------------------------------------------------------------- ; Search for the address of the first matching image. @@ -2921,21 +2925,7 @@ class ImagePut { imagesearchall2 := this.Base64Code((A_PtrSize == 4) ? "" - : "QVdBVkFVQVRVV1ZTSIPsSIuEJNAAAACLtCTIAAAARImMJKgAAABED7eMJNgAAABIiYwkkAAAAImUJJgAAABMiYQkoAAAAIXAD4Xa" - . "AwAARIuUJMAAAACJ8kSLnCTAAAAAweoCD6+UJMAAAACLjCTAAAAARA+v1kHB6wJIi7wkuAAAAESJ2EgBwkWJ0EiNFJdMAcFIjRyP" - . "SDnaD4MOAwAARIuEJMAAAABB0ehJweACSo0MAkg50XcW6ZMDAAAPH0AASIPCBEg50Q+G1AIAAIB6AwB07UiJ0EgrhCS4AAAAMdJI" - . "wfgC97QkwAAAAGaJVCQwRA+3wg+30InRD6+MJMAAAACJVCQ0TAHBSMHhAkiLhCS4AAAASIu8JKAAAABEi6wkqAAAAEQrrCTAAAAA" - . "iwQIi4wksAAAACnxD6+MJKgAAABIjSyPSDnvD4PtAgAAD6+UJKgAAABJiftFicrHRCQsAAAAAEH32kwBwkiNPJUAAAAAi5QkwAAA" - . "AEiNXwFIiXwkCEiDxwJIiVwkEIucJKgAAABIiXwkIEiNPJUAAAAASYncSIlcJDiLnCTAAAAASSnUjVP/ScHkAkiNHJUAAAAAD7bQ" - . "ZolUJCgPttTB6BAPtsBIiRwkMduJVCQcZolEJCrrFg8fgAAAAABMAxwkMdtJOesPgwoBAABEOet37EiLRCQIQQ+2FAMPt0QkKCnQ" - . "ZkE5wXMKZkQ50A+CyAAAAEiLRCQQQQ+2FAMPt0QkHCnQZkE5wXMKZkQ50A+CpwAAAEiLRCQgQQ+2FAMPt0QkKinQZkE5wXMKZkQ5" - . "0A+ChgAAAEiLhCS4AAAATInaRTH/hfYPhNsAAABMjQQ4STnAdxvpzQAAAA8fRAAASIPABEiDwgRJOcAPhqcAAACAeAMAdOkPtghE" - . "D7YyRCnxZkE5yXMGZkQ50XIwD7ZIAUQPtnIBRCnxZkE5yXMGZkQ50XIYD7ZIAkQPtnICRCnxZkE5yXOpZkQ50XOjSYPDBIPDATHA" - . "O5wkqAAAAA9D2Ek56w+C9v7//4tEJCxIi7QkkAAAAAHASI0EhkiJhCSQAAAASInGi0QkMMHgEAtEJDSJBotEJCxIg8RIW15fXUFc" - . "QV1BXkFfw0GDxwFMAeJEOf4PhSX///+LTCQsOYwkmAAAAHYwTInYSCuEJKAAAABIwfgCSJlI93wkOGYPbsJIi5QkkAAAAGYPOiLA" - . "AY0ECWYP1gSCg0QkLAFJAfsDnCTAAAAA6Uv///9MAcJIOdMPhwH9//9Ii7wkuAAAADHJRTHAMdJmRIlEJDCAfA8DAIlUJDQPhTv9" - . "//+LjCTAAAAAQY1T/0QrlCTAAAAASMHgAkwB0kj32EQp2UiNFJdIweECSPfZSYnQSQHAchXrUWYuDx+EAAAAAABIg+oESTnQcz6A" - . "egMAdPHpr/z//w8fQABBicBBwegQZkSJRCQw6br8///HRCQsAAAAAEiLtCSQAAAA6c/+//9IicrpTf///0gByuug") + : "QVdBVkFVQVRVV1ZTSIPsSIuEJNgAAABEi5QkwAAAAEiLnCS4AAAAi7wk4AAAAImUJJgAAACJwkEPr8FMjWwkPEEPr9JIiYwkkAAAAIuMJNAAAABIAchIAcpIweACMcmLFJNIiUQkEESJyESJy0Qp04lUJDyLlCSwAAAAK5QkyAAAAIlcJCRBD6/RSY00kESJ0kiJdCQoSCnQif5MjSSVAAAAAEjB4AL33kiJRCQYQY1C/2aJdCQiSMHgAkiJRCQIMcBIi3QkKEk58A+D2QAAADlEJCRzDUiLRCQISQHA6b8AAABIi3QkEDHSSY0cMEYPthwqD7Y0E0Ep82ZEOd9zCGZEO1wkInJUSP/CSIP6A3XdSIuUJLgAAABNicMx7esKSItcJBj/xUkB2zusJMgAAAB0RE6NNCJMOfJz5IB6AwB0KzHbD7Y0GkUPtjwbRCn+Zjn3cw9mO3QkInMISYPABP/A6zVI/8NIg/sDdddIg8IESYPDBOvAO4wkmAAAAHMRRYsYSIucJJAAAACJykSJHJP/wU0B4EQB0EQ5yA+CIP///zHA6Rn///+JyEiDxEhbXl9dQVxBXUFeQV/D") ; -------------------------------------------------------------------------------------------------------- From c868eb25718a20454628e655708db36f04f0113c Mon Sep 17 00:00:00 2001 From: "Gunwoo Gim (il debole)" Date: Sun, 17 Dec 2023 13:21:21 +0900 Subject: [PATCH 487/492] Fix bug where the last scanline was skipped --- source/imagesearch2.c | 2 +- source/imagesearchall2.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/imagesearch2.c b/source/imagesearch2.c index 30d66de2..db3e0141 100644 --- a/source/imagesearch2.c +++ b/source/imagesearch2.c @@ -71,7 +71,7 @@ unsigned int imagesearch2(unsigned int * restrict result, unsigned int * start, // Start the search. unsigned int left = 0; - while ( current < end ) { + while ( current <= end ) { unsigned int offset = current - start; //unsigned int left = offset % width; diff --git a/source/imagesearchall2.c b/source/imagesearchall2.c index 4111d01c..2a1d7eed 100644 --- a/source/imagesearchall2.c +++ b/source/imagesearchall2.c @@ -70,7 +70,7 @@ unsigned int imagesearchall2(unsigned int * restrict result, unsigned int capaci // Start the search. unsigned int left = 0; - while ( current < end ) { + while ( current <= end ) { unsigned int offset = current - start; //unsigned int left = offset % width; From f50b1ba72406ce938081fb5805c432b5cb36f4b2 Mon Sep 17 00:00:00 2001 From: "Gunwoo Gim (il debole)" Date: Sun, 17 Dec 2023 13:25:23 +0900 Subject: [PATCH 488/492] The previous fix didn't fix, this one does seem to fix it --- source/imagesearch2.c | 2 +- source/imagesearchall2.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/imagesearch2.c b/source/imagesearch2.c index db3e0141..cc4b9f63 100644 --- a/source/imagesearch2.c +++ b/source/imagesearch2.c @@ -67,7 +67,7 @@ unsigned int imagesearch2(unsigned int * restrict result, unsigned int * start, unsigned int range_height = height - h; unsigned int * current = start; - unsigned int * end = start + width * range_height; + unsigned int * end = start + width * range_height + width; // Start the search. unsigned int left = 0; diff --git a/source/imagesearchall2.c b/source/imagesearchall2.c index 2a1d7eed..c4699ecd 100644 --- a/source/imagesearchall2.c +++ b/source/imagesearchall2.c @@ -66,7 +66,7 @@ unsigned int imagesearchall2(unsigned int * restrict result, unsigned int capaci unsigned int range_height = height - h; unsigned int * current = start; - unsigned int * end = start + width * range_height; + unsigned int * end = start + width * range_height + width; // Start the search. unsigned int left = 0; From 2aa684377d5507216fd3ff386d4b914108c25cbe Mon Sep 17 00:00:00 2001 From: "Gunwoo Gim (il debole)" Date: Sun, 17 Dec 2023 13:35:21 +0900 Subject: [PATCH 489/492] The prev. commit had a bug of the possibility of reaching off haystack --- source/imagesearch2.c | 2 +- source/imagesearchall2.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/imagesearch2.c b/source/imagesearch2.c index cc4b9f63..0d7c75c0 100644 --- a/source/imagesearch2.c +++ b/source/imagesearch2.c @@ -71,7 +71,7 @@ unsigned int imagesearch2(unsigned int * restrict result, unsigned int * start, // Start the search. unsigned int left = 0; - while ( current <= end ) { + while ( current < end ) { unsigned int offset = current - start; //unsigned int left = offset % width; diff --git a/source/imagesearchall2.c b/source/imagesearchall2.c index c4699ecd..3a2529d7 100644 --- a/source/imagesearchall2.c +++ b/source/imagesearchall2.c @@ -70,7 +70,7 @@ unsigned int imagesearchall2(unsigned int * restrict result, unsigned int capaci // Start the search. unsigned int left = 0; - while ( current <= end ) { + while ( current < end ) { unsigned int offset = current - start; //unsigned int left = offset % width; From a5524951f80e9cc39521ea7b72cfd867169c06d6 Mon Sep 17 00:00:00 2001 From: Edison Hua Date: Sun, 24 Dec 2023 22:24:22 -0500 Subject: [PATCH 490/492] comments: when the faeries dance in the wind --- ImagePut (for v1).ahk | 9 +++++---- ImagePut.ahk | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/ImagePut (for v1).ahk b/ImagePut (for v1).ahk index 31ff9b86..f663c633 100644 --- a/ImagePut (for v1).ahk +++ b/ImagePut (for v1).ahk @@ -178,8 +178,8 @@ ImageEqual(images*) { class ImagePut { - static decode := False ; Forces conversion using a bitmap. The original file encoding will be lost. - static validate := False ; Always copies image data into memory instead of passing references. + static decode := False ; Decompresses image to a pixel buffer. Any encoding such as JPG will be lost. + static validate := False ; Always copies pixels to new memory immediately instead of copy-on-read/write. call(cotype, image, p*) { @@ -218,8 +218,9 @@ class ImagePut { ; #2 - Fallback to GDI+ bitmap as the intermediate. else { ; GdipImageForceValidation must be called immediately or it fails without any errors. - ; It load the image pixels to the bitmap buffer, increasing memory usage and prevents - ; changes to the pixels while bypassing any copy-on-write and copy on LockBits(read) behavior. + ; Doing so loads the pixels to the bitmap buffer. Increases memory usage. + ; Prevents future changes to the original pixels from altering any copies. + ; Without validation, it preforms copy-on-write and copy on LockBits(read). ; Convert via GDI+ bitmap intermediate. if !(pBitmap := this.ToBitmap(type, image, keywords)) diff --git a/ImagePut.ahk b/ImagePut.ahk index d2c7f9d5..c24c368e 100644 --- a/ImagePut.ahk +++ b/ImagePut.ahk @@ -178,8 +178,8 @@ ImageEqual(images*) { class ImagePut { - static decode := False ; Forces conversion using a bitmap. The original file encoding will be lost. - static validate := False ; Always copies image data into memory instead of passing references. + static decode := False ; Decompresses image to a pixel buffer. Any encoding such as JPG will be lost. + static validate := False ; Always copies pixels to new memory immediately instead of copy-on-read/write. static call(cotype, image, p*) { @@ -218,8 +218,9 @@ class ImagePut { ; #2 - Fallback to GDI+ bitmap as the intermediate. else { ; GdipImageForceValidation must be called immediately or it fails without any errors. - ; It load the image pixels to the bitmap buffer, increasing memory usage and prevents - ; changes to the pixels while bypassing any copy-on-write and copy on LockBits(read) behavior. + ; Doing so loads the pixels to the bitmap buffer. Increases memory usage. + ; Prevents future changes to the original pixels from altering any copies. + ; Without validation, it preforms copy-on-write and copy on LockBits(read). ; Convert via GDI+ bitmap intermediate. if !(pBitmap := this.ToBitmap(type, image, keywords)) From a0b9226dcba358ad7e022140b05c28e415298937 Mon Sep 17 00:00:00 2001 From: "Gunwoo Gim (il debole)" Date: Tue, 2 Jan 2024 10:10:31 +0900 Subject: [PATCH 491/492] Remove an unnecessary conditional jump --- source/pixelsearch1x.c | 57 +++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/source/pixelsearch1x.c b/source/pixelsearch1x.c index c1c3f377..d840e0da 100644 --- a/source/pixelsearch1x.c +++ b/source/pixelsearch1x.c @@ -1,28 +1,49 @@ #include +// The number of vector registors to utilize in each innermost loop +#define NR_VEC 4 + unsigned int * pixelsearch1x(unsigned int * start, unsigned int * end, unsigned int color) { + // The number of elements in each vector register + size_t nr_elems_in_vec = sizeof(__m128i) / sizeof(*start); // Create a vector of four copies of the target color. __m128i vcolor = _mm_set1_epi32(color); // Loop over start pointer with a step of four unsigned integers. - while (start < end - 3) { - - // Load four unsigned integers from start into a vector. - __m128i vstart = _mm_loadu_si128((__m128i *) start); - - // Compare vstart and vcolor for equality. - __m128i vcmp = _mm_cmpeq_epi32(vstart, vcolor); - - // Create a mask from each byte (using the most significant bit) in vcmp. - int mask = _mm_movemask_epi8(vcmp); - - // If the mask is nonzero, there is at least one match. - if (mask != 0) - break; - - // Increment start by four unsigned integers. - start += 4; + while ( start < end - (nr_elems_in_vec * NR_VEC) + 1 ) { + __m128i vcmp[NR_VEC]; + + for ( int i = 0; i < NR_VEC; i++ ) { + // Load four unsigned integers from start into a vector. + __m128i vstart = _mm_loadu_si128( ((__m128i *) start) + i ); + + // Compare vstart and vcolor for equality. + vcmp[i] = _mm_cmpeq_epi32(vstart, vcolor); + } + + // Use POR because it has big a throughput + __m128i vmask = _mm_or_si128(vcmp[0], vcmp[1]); + for ( int i = 2; i < NR_VEC; i++ ) { + vmask = _mm_or_si128(vmask, vcmp[i]); + } + + // If the result is nonzero, there is at least one match. + // This combination of MOVMSKBPS + TEST can be replaced with a PTEST when SSE4.1 is available. + if ( _mm_movemask_ps((__m128) vmask) ) { + int mask = 0; + for ( int i = 0; i < NR_VEC; i++ ) { + // Create a mask from each dword (using the most significant bit) in vcmp. + mask |= _mm_movemask_ps((__m128) vcmp[i]) << nr_elems_in_vec * i; + } + + // Return the pointer to the pixel with matching color. + // _tzcnt_u32 can be used instead of __builtin_ctz since they're almost identical. + return start + __builtin_ctz(mask); + } + + // Increment start for the next batch. + start += nr_elems_in_vec * NR_VEC; } // Clean up any remaining elements. @@ -33,4 +54,4 @@ unsigned int * pixelsearch1x(unsigned int * start, unsigned int * end, unsigned } return start; // start == end if no match. -} \ No newline at end of file +} From 86a3c75783d7065dd77ec8a37a9744e0466daac9 Mon Sep 17 00:00:00 2001 From: "Gunwoo Gim (il debole)" Date: Sun, 14 Jan 2024 21:07:26 +0900 Subject: [PATCH 492/492] The typo in a line of comment "has big a throughput" --- source/pixelsearch1x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/pixelsearch1x.c b/source/pixelsearch1x.c index d840e0da..302eb67f 100644 --- a/source/pixelsearch1x.c +++ b/source/pixelsearch1x.c @@ -22,7 +22,7 @@ unsigned int * pixelsearch1x(unsigned int * start, unsigned int * end, unsigned vcmp[i] = _mm_cmpeq_epi32(vstart, vcolor); } - // Use POR because it has big a throughput + // Use POR because it has a big throughput __m128i vmask = _mm_or_si128(vcmp[0], vcmp[1]); for ( int i = 2; i < NR_VEC; i++ ) { vmask = _mm_or_si128(vmask, vcmp[i]);