;###########################################################
; Script: Vis2.ahk
; Author: iseahound
; Date: 2017-08-19
; Recent: 2018-04-04
; https://www.autohotkey.com/boards/viewtopic.php?f=6&t=36047
; Modified by Pulover
;###########################################################
; OCR() - Convert pictures of text into text.
OCR(image:="", language:="", options:=""){
return Vis2.OCR(image, language, options)
}
class Vis2 {
class ImageIdentify extends Vis2.functor {
call(self, image:="", search:="", options:=""){
return (image != "") ? (new Vis2.provider.GoogleCloudVision()).ImageIdentify(image, search, options)
: Vis2.core.returnText({"provider":(new Vis2.provider.GoogleCloudVision(search)), "tooltip":"Image Identification Tool", "splashImage":true})
}
}
class OCR extends Vis2.functor {
call(self, image:="", language:="", options:=""){
return (image != "") ? (new Vis2.provider.Tesseract()).OCR(image, language, options)
: Vis2.core.returnText({"provider":(new Vis2.provider.Tesseract(language)), "tooltip":"Optical Character Recognition Tool", "textPreview":true})
}
}
class core {
; returnText() is a wrapper function of Vis2.core.ux.start()
; Unlike Vis2.core.ux.start(), this function will return a string of text.
returnText(obj := ""){
obj := IsObject(obj) ? obj : {}
obj.callback := "returnText"
if (Vis2.core.ux.start(obj) == "") {
while !(EXITCODE := Vis2.obj.EXITCODE)
Sleep 1
text := Vis2.obj.database
Vis2.obj.callbackConfirmed := true
text.base.google := ObjBindMethod(Vis2.Text, "google")
text.base.clipboard := ObjBindMethod(Vis2.Text, "clipboard")
return (EXITCODE > 0) ? text : ""
}
}
}
class functor {
__Call(method, ByRef arg := "", args*) {
; When casting to Call(), use a new instance of the "function object"
; so as to avoid directly storing the properties(used across sub-methods)
; into the "function object" itself.
; Thanks to coco for this code. Modified by iseahound.
if IsObject(method)
return (new this).Call(method, arg, args*)
else if (method == "")
return (new this).Call(arg, args*)
}
}
class Graphics {
static pToken, Gdip := 0
Startup(){
global pToken
return Vis2.Graphics.pToken := (Vis2.Graphics.Gdip++ > 0) ? Vis2.Graphics.pToken : (pToken) ? pToken : Gdip_Startup()
}
Shutdown(){
global pToken
return Vis2.Graphics.pToken := (--Vis2.Graphics.Gdip <= 0) ? ((pToken) ? pToken : Gdip_Shutdown(Vis2.Graphics.pToken)) : Vis2.Graphics.pToken
}
Name(){
VarSetCapacity(UUID, 16, 0)
if (DllCall("rpcrt4.dll\UuidCreate", "ptr", &UUID) != 0)
return (ErrorLevel := 1) & 0
if (DllCall("rpcrt4.dll\UuidToString", "ptr", &UUID, "uint*", suuid) != 0)
return (ErrorLevel := 2) & 0
return A_TickCount "n" SubStr(StrGet(suuid), 1, 8), DllCall("rpcrt4.dll\RpcStringFree", "uint*", suuid)
}
}
class provider {
class Tesseract {
static leptonica := A_ScriptDir "\bin\leptonica_util\leptonica_util.exe"
static tesseract := A_ScriptDir "\bin\tesseract\tesseract.exe"
static tessdata_best := (FileExist(A_ScriptDir "\MacroCreator.ini") ? A_ScriptDir : A_AppData "\MacroCreator")
. "\bin\tesseract\tessdata_best"
static tessdata_fast := (FileExist(A_ScriptDir "\MacroCreator.ini") ? A_ScriptDir : A_AppData "\MacroCreator")
. "\bin\tesseract\tessdata_fast"
uuid := Vis2.stdlib.CreateUUID()
file := A_Temp "\Vis2_screenshot" this.uuid ".bmp"
fileProcessedImage := A_Temp "\Vis2_preprocess" this.uuid ".tif"
fileConvertedText := A_Temp "\Vis2_text" this.uuid ".txt"
; public OCR()
; public preprocess()
; public convert()
; public cleanup()
; public getPreprocessImage()
; public getText()
; private convert_best()
; private convert_fast()
; private getTextLines()
__New(language:=""){
this.language := language
}
OCR(image, language:="", options:=""){
this.language := language
try {
screenshot := Vis2.stdlib.toFile(image, this.file, options)
this.preprocess(screenshot, this.fileProcessedImage)
this.convert_best(this.fileProcessedImage, this.fileConvertedText)
text := this.getText(this.fileConvertedText)
} catch e {
MsgBox, 16,, % "Exception thrown!`n`nwhat: " e.what "`nfile: " e.file
. "`nline: " e.line "`nmessage: " e.message "`nextra: " e.extra
}
finally {
this.cleanup()
}
return text
}
cleanup(){
FileDelete, % this.file
FileDelete, % this.fileProcessedImage
FileDelete, % this.fileConvertedText
}
convert(in:="", out:="", fast:=1){
in := (in) ? in : this.fileProcessedImage
out := (out) ? out : this.fileConvertedText
fast := (fast) ? this.tessdata_fast : this.tessdata_best
if !(FileExist(in))
throw Exception("Input image for conversion not found.",, in)
if !(FileExist(this.tesseract))
throw Exception("Tesseract not found",, this.tesseract)
static q := Chr(0x22)
_cmd .= q this.tesseract q " --tessdata-dir " q fast q " " q in q " " q SubStr(out, 1, -4) q
_cmd .= (this.language) ? " -l " q this.language q : ""
_cmd := ComSpec " /C " q _cmd q
RunWait % _cmd,, Hide
if !(FileExist(out))
throw Exception("Tesseract failed.",, _cmd)
return out
}
convert_best(in:="", out:=""){
return this.convert(in, out, 0)
}
convert_fast(in:="", out:=""){
return this.convert(in, out, 1)
}
getPreprocessImage(){
return this.fileProcessedImage
}
getText(in:="", lines:=""){
in := (in) ? in : this.fileConvertedText
if !(database := FileOpen(in, "r`n", "UTF-8"))
throw Exception("Text file could not be found or opened.",, in)
if (lines == "") {
text := RegExReplace(database.Read(), "^\s*(.*?)\s*$", "$1")
text := RegExReplace(text, "(?<!\r)\n", "`r`n")
} else {
while (lines > 0) {
data := database.ReadLine()
data := RegExReplace(data, "^\s*(.*?)\s*$", "$1")
if (data != "") {
text .= (text) ? ("`n" . data) : data
lines--
}
if (!database || database.AtEOF)
break
}
}
database.Close()
return text
}
getTextLines(lines){
return this.read(, lines)
}
preprocess(in:="", out:=""){
static ocrPreProcessing := 1
static negateArg := 2
static performScaleArg := 1
static scaleFactor := 3.5
in := (in != "") ? in : this.file
out := (out != "") ? out : this.fileProcessedImage
if !(FileExist(in))
throw Exception("Input image for preprocessing not found.",, in)
if !(FileExist(this.leptonica))
throw Exception("Leptonica not found",, this.leptonica)
static q := Chr(0x22)
_cmd .= q this.leptonica q " " q in q " " q out q
_cmd .= " " negateArg " 0.5 " performScaleArg " " scaleFactor " " ocrPreProcessing " 5 2.5 " ocrPreProcessing " 2000 2000 0 0 0.0"
_cmd := ComSpec " /C " q _cmd q
RunWait, % _cmd,, Hide
if !(FileExist(out))
throw Exception("Preprocessing failed.",, _cmd)
return out
}
}
}
class stdlib {
isBinaryImageFormat(data){
Loop 12
bytes .= Chr(NumGet(data, A_Index-1, "uchar"))
; Null bytes are not passed, so they have been omitted below
if (bytes ~= "^BM")
return "bmp"
if (bytes ~= "^(GIF87a|GIF89a)")
return "gif"
if (bytes ~= "^ÿØÿÛ")
return "jpg"
if (bytes ~= "s)^ÿØÿà..\x4A\x46\x49\x46") ;\x00\x01
return "jfif"
if (bytes ~= "^\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")
return "png"
if (bytes ~= "^(\x49\x49\x2A|\x4D\x4D\x2A)") ; 49 49 2A 00, 4D 4D 00 2A
return "tif"
return
}
isURL(url){
regex .= "((https?|ftp)\:\/\/)" ; SCHEME
regex .= "([a-z0-9+!*(),;?&=\$_.-]+(\:[a-z0-9+!*(),;?&=\$_.-]+)?@)?" ; User and Pass
regex .= "([a-z0-9-.]*)\.([a-z]{2,3})" ; Host or IP
regex .= "(\:[0-9]{2,5})?" ; Port
regex .= "(\/([a-z0-9+\$_-]\.?)+)*\/?" ; Path
regex .= "(\?[a-z+&\$_.-][a-z0-9;:@&%=+\/\$_.-]*)?" ; GET Query
regex .= "(#[a-z_.-][a-z0-9+\$_.-]*)?" ; Anchor
return (url ~= "i)" regex) ? true : false
}
b64Encode( ByRef buf, bufLen:="" ) {
bufLen := (bufLen) ? bufLen : StrLen(buf) << !!A_IsUnicode
DllCall( "crypt32\CryptBinaryToStringA", "ptr", &buf, "UInt", bufLen, "Uint", 1 | 0x40000000, "Ptr", 0, "UInt*", outLen )
VarSetCapacity( outBuf, outLen, 0 )
DllCall( "crypt32\CryptBinaryToStringA", "ptr", &buf, "UInt", bufLen, "Uint", 1 | 0x40000000, "Ptr", &outBuf, "UInt*", outLen )
return strget( &outBuf, outLen, "CP0" )
}
b64Decode( b64str, ByRef outBuf ) {
static CryptStringToBinary := "crypt32\CryptStringToBinary" (A_IsUnicode ? "W" : "A")
DllCall( CryptStringToBinary, "ptr", &b64str, "UInt", 0, "Uint", 1, "Ptr", 0, "UInt*", outLen, "ptr", 0, "ptr", 0 )
VarSetCapacity( outBuf, outLen, 0 )
DllCall( CryptStringToBinary, "ptr", &b64str, "UInt", 0, "Uint", 1, "Ptr", &outBuf, "UInt*", outLen, "ptr", 0, "ptr", 0 )
return outLen
}
CreateUUID() {
VarSetCapacity(puuid, 16, 0)
if !(DllCall("rpcrt4.dll\UuidCreate", "ptr", &puuid))
if !(DllCall("rpcrt4.dll\UuidToString", "ptr", &puuid, "uint*", suuid))
return StrGet(suuid), DllCall("rpcrt4.dll\RpcStringFree", "uint*", suuid)
return ""
}
Gdip_EncodeBitmapTo64string(pBitmap, ext, Quality=75) {
if Ext not in BMP,DIB,RLE,JPG,JPEG,JPE,JFIF,GIF,TIF,TIFF,PNG
return -1
Extension := "." Ext
DllCall("gdiplus\GdipGetImageEncodersSize", "uint*", nCount, "uint*", nSize)
VarSetCapacity(ci, nSize)
DllCall("gdiplus\GdipGetImageEncoders", "uint", nCount, "uint", nSize, Ptr, &ci)
if !(nCount && nSize)
return -2
Loop, %nCount%
{
sString := StrGet(NumGet(ci, (idx := (48+7*A_PtrSize)*(A_Index-1))+32+3*A_PtrSize), "UTF-16")
if !InStr(sString, "*" Extension)
continue
pCodec := &ci+idx
break
}
if !pCodec
return -3
if (Quality != 75)
{
Quality := (Quality < 0) ? 0 : (Quality > 100) ? 100 : Quality
if Extension in .JPG,.JPEG,.JPE,.JFIF
{
DllCall("gdiplus\GdipGetEncoderParameterListSize", Ptr, pBitmap, Ptr, pCodec, "uint*", nSize)
VarSetCapacity(EncoderParameters, nSize, 0)
DllCall("gdiplus\GdipGetEncoderParameterList", Ptr, pBitmap, Ptr, pCodec, "uint", nSize, Ptr, &EncoderParameters)
Loop, % NumGet(EncoderParameters, "UInt")
{
elem := (24+(A_PtrSize ? A_PtrSize : 4))*(A_Index-1) + 4 + (pad := A_PtrSize = 8 ? 4 : 0)
if (NumGet(EncoderParameters, elem+16, "UInt") = 1) && (NumGet(EncoderParameters, elem+20, "UInt") = 6)
{
p := elem+&EncoderParameters-pad-4
NumPut(Quality, NumGet(NumPut(4, NumPut(1, p+0)+20, "UInt")), "UInt")
break
}
}
}
}
DllCall("ole32\CreateStreamOnHGlobal", "ptr",0, "int",true, "ptr*",pStream)
DllCall("gdiplus\GdipSaveImageToStream", "ptr",pBitmap, "ptr",pStream, "ptr",pCodec, "uint",p ? p : 0)
DllCall("ole32\GetHGlobalFromStream", "ptr",pStream, "uint*",hData)
pData := DllCall("GlobalLock", "ptr",hData, "uptr")
nSize := DllCall("GlobalSize", "uint",pData)
VarSetCapacity(Bin, nSize, 0)
DllCall("RtlMoveMemory", "ptr",&Bin , "ptr",pData , "uint",nSize)
DllCall("GlobalUnlock", "ptr",hData)
DllCall(NumGet(NumGet(pStream + 0, 0, "uptr") + (A_PtrSize * 2), 0, "uptr"), "ptr",pStream)
DllCall("GlobalFree", "ptr",hData)
DllCall("Crypt32.dll\CryptBinaryToString", "ptr",&Bin, "uint",nSize, "uint",0x01, "ptr",0, "uint*",base64Length)
VarSetCapacity(base64, base64Length*2, 0)
DllCall("Crypt32.dll\CryptBinaryToString", "ptr",&Bin, "uint",nSize, "uint",0x01, "ptr",&base64, "uint*",base64Length)
Bin := ""
VarSetCapacity(Bin, 0)
VarSetCapacity(base64, -1)
return base64
}
Gdip_BitmapFromClientHWND(hwnd) {
VarSetCapacity(rc, 16)
DllCall("GetClientRect", "ptr", hwnd, "ptr", &rc)
hbm := CreateDIBSection(NumGet(rc, 8, "int"), NumGet(rc, 12, "int"))
VarSetCapacity(rc, 0)
hdc := CreateCompatibleDC()
obm := SelectObject(hdc, hbm)
PrintWindow(hwnd, hdc, 1)
pBitmap := Gdip_CreateBitmapFromHBITMAP(hbm)
SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc)
return pBitmap
}
Gdip_CropBitmap(ByRef pBitmap, c, preserveOriginal:=false){
w := Gdip_GetImageWidth(pBitmap), h := Gdip_GetImageHeight(pBitmap)
pBitmap2 := Gdip_CloneBitmapArea(pBitmap, c.1, c.2, (c.1 + c.3 > w) ? w - c.1 : c.3 , (c.2 + c.4 > h) ? h - c.2 : c.4)
(preserveOriginal) ? "" : Gdip_DisposeImage(pBitmap)
pBitmap := pBitmap2
}
Gdip_isBitmapEqual(pBitmap1, pBitmap2, width:="", height:="") {
; Check if pointers are identical.
if (pBitmap1 == pBitmap2)
return true
; Assume both Bitmaps are equal in width and height.
width := (width) ? width : Gdip_GetImageWidth(pBitmap1)
height := (height) ? height : Gdip_GetImageHeight(pBitmap1)
E1 := Gdip_LockBits(pBitmap1, 0, 0, width, height, Stride1, Scan01, BitmapData1)
E2 := Gdip_LockBits(pBitmap2, 0, 0, width, height, Stride2, Scan02, BitmapData2)
; RtlCompareMemory preforms an unsafe comparison stopping at the first different byte.
length := width * height * 4 ; ARGB = 4 bytes
bytes := DllCall("RtlCompareMemory", "ptr", Scan01+0, "ptr", Scan02+0, "uint", length)
Gdip_UnlockBits(pBitmap1, BitmapData1)
Gdip_UnlockBits(pBitmap2, BitmapData2)
return (bytes == length) ? true : false
}
RPath_Absolute(AbsolutPath, RelativePath, s="\") {
len := InStr(AbsolutPath, s, "", InStr(AbsolutPath, s . s) + 2) - 1 ;get server or drive string length
pr := SubStr(AbsolutPath, 1, len) ;get server or drive name
AbsolutPath := SubStr(AbsolutPath, len + 1) ;remove server or drive from AbsolutPath
If InStr(AbsolutPath, s, "", 0) = StrLen(AbsolutPath) ;remove last \ from AbsolutPath if any
StringTrimRight, AbsolutPath, AbsolutPath, 1
If InStr(RelativePath, s) = 1 ;when first char is \ go to AbsolutPath of server or drive
AbsolutPath := "", RelativePath := SubStr(RelativePath, 2) ;set AbsolutPath to nothing and remove one char from RelativePath
Else If InStr(RelativePath,"." s) = 1 ;when first two chars are .\ add to current AbsolutPath directory
RelativePath := SubStr(RelativePath, 3) ;remove two chars from RelativePath
Else If InStr(RelativePath,".." s) = 1 { ;otherwise when first 3 char are ..\
StringReplace, RelativePath, RelativePath, ..%s%, , UseErrorLevel ;remove all ..\ from RelativePath
Loop, %ErrorLevel% ;for all ..\
AbsolutPath := SubStr(AbsolutPath, 1, InStr(AbsolutPath, s, "", 0) - 1) ;remove one folder from AbsolutPath
} Else ;relative path does not need any substitution
pr := "", AbsolutPath := "", s := "" ;clear all variables to just return RelativePath
Return, pr . AbsolutPath . s . RelativePath ;concatenate server + AbsolutPath + separator + RelativePath
}
setSystemCursor(CursorID = "", cx = 0, cy = 0 ) { ; Thanks to Serenity - https://autohotkey.com/board/topic/32608-changing-the-system-cursor/
static SystemCursors := "32512,32513,32514,32515,32516,32640,32641,32642,32643,32644,32645,32646,32648,32649,32650,32651"
Loop, Parse, SystemCursors, `,
{
Type := "SystemCursor"
CursorHandle := DllCall( "LoadCursor", "uInt",0, "Int",CursorID )
%Type%%A_Index% := DllCall( "CopyImage", "uInt",CursorHandle, "uInt",0x2, "Int",cx, "Int",cy, "uInt",0 )
CursorHandle := DllCall( "CopyImage", "uInt",%Type%%A_Index%, "uInt",0x2, "Int",0, "Int",0, "Int",0 )
DllCall( "SetSystemCursor", "uInt",CursorHandle, "Int",A_Loopfield)
}
}
; toBase64() - Converts the input to a Base 64 string.
; Types of input accepted
; Objects: Rectangle Array (Screenshot)
; Strings: File, URL, Window Title (ahk_class...) OR hwnd (hex)
; Numbers: GDI Bitmap, GDI HBitmap
; Rawfile: Binary, base64
toBase64(image, extension:="png", quality:="", crop:="", crop2:=""){
Vis2.Graphics.Startup()
; Check if image is an array of 4 numbers
if (image.1 ~= "^\d+$" && image.2 ~= "^\d+$" && image.3 ~= "^\d+$" && image.4 ~= "^\d+$") {
pBitmap := Gdip_BitmapFromScreen(image.1 "|" image.2 "|" image.3 "|" image.4)
base64 := Vis2.stdlib.Gdip_EncodeBitmapTo64string(pBitmap, extension, quality)
Gdip_DisposeImage(pBitmap)
}
; Check if image points to a valid file
else if FileExist(image) {
if !(crop) {
file := FileOpen(image, "r")
file.RawRead(data, file.length)
base64 := Vis2.stdlib.b64Encode(data, file.length)
file.Close()
} else {
pBitmap := Gdip_CreateBitmapFromFile(image)
(crop) ? Vis2.stdlib.Gdip_CropBitmap(pBitmap, crop) : ""
base64 := Vis2.stdlib.Gdip_EncodeBitmapTo64string(pBitmap, extension, quality)
Gdip_DisposeImage(pBitmap)
}
}
; Check if image points to a valid URL
else if Vis2.stdlib.isURL(image) {
static req := ComObjCreate("WinHttp.WinHttpRequest.5.1")
req.Open("GET",image)
req.Send()
pStream := ComObjQuery(req.ResponseStream, "{0000000C-0000-0000-C000-000000000046}")
if !(crop) {
DllCall("ole32\GetHGlobalFromStream", "ptr",pStream, "uint*",hData)
pData := DllCall("GlobalLock", "ptr",hData, "uptr")
nSize := DllCall("GlobalSize", "uint",pData)
VarSetCapacity(Bin, nSize, 0)
DllCall("RtlMoveMemory", "ptr",&Bin , "ptr",pData , "uint",nSize)
DllCall("GlobalUnlock", "ptr",hData)
DllCall(NumGet(NumGet(pStream + 0, 0, "uptr") + (A_PtrSize * 2), 0, "uptr"), "ptr",pStream)
DllCall("GlobalFree", "ptr",hData)
DllCall("Crypt32.dll\CryptBinaryToString", "ptr",&Bin, "uint",nSize, "uint",0x01, "ptr",0, "uint*",base64Length)
VarSetCapacity(base64, base64Length*2, 0)
DllCall("Crypt32.dll\CryptBinaryToString", "ptr",&Bin, "uint",nSize, "uint",0x01, "ptr",&base64, "uint*",base64Length)
Bin := ""
VarSetCapacity(Bin, 0)
VarSetCapacity(base64, -1)
} else {
DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr",pStream, "uptr*",pBitmap)
ObjRelease(pStream)
(crop) ? Vis2.stdlib.Gdip_CropBitmap(pBitmap, crop) : ""
base64 := Vis2.stdlib.Gdip_EncodeBitmapTo64string(pBitmap, extension, quality)
Gdip_DisposeImage(pBitmap)
}
}
; Check if image matches a window title OR is a valid handle to a window
else if (DllCall("IsWindow", "ptr",image) || (hwnd := WinExist(image))) {
hwnd := (DllCall("IsWindow", "ptr",image)) ? image : hwnd
pBitmap := Vis2.stdlib.Gdip_BitmapFromClientHWND(hwnd)
(crop) ? Vis2.stdlib.Gdip_CropBitmap(pBitmap, crop) : ""
base64 := Vis2.stdlib.Gdip_EncodeBitmapTo64string(pBitmap, extension, quality)
Gdip_DisposeImage(pBitmap)
}
; Check if image is a valid GDI Bitmap
else if DeleteObject(Gdip_CreateHBITMAPFromBitmap(image)) {
(crop) ? Vis2.stdlib.Gdip_CropBitmap(image, crop, true) : ""
base64 := Vis2.stdlib.Gdip_EncodeBitmapTo64string(image, extension, quality)
(crop) ? Gdip_DisposeImage(image) : ""
}
; Check if image is a valid handle to a GDI Bitmap
else if (DllCall("GetObjectType", "ptr",image) == 7) {
pBitmap := Gdip_CreateBitmapFromHBITMAP(image)
(crop) ? Vis2.stdlib.Gdip_CropBitmap(pBitmap, crop) : ""
base64 := Vis2.stdlib.Gdip_EncodeBitmapTo64string(pBitmap, extension, quality)
Gdip_DisposeImage(pBitmap)
}
; Check if image is a base64 string
else if (image ~= "^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$") {
base64 := image
}
Vis2.Graphics.Shutdown()
return base64
}
; toFile() - Saves the image as a temporary file.
toFile(image, outputFile:="", crop:=""){
Vis2.Graphics.Startup()
; Check if image is an array of 4 numbers
if (image.1 ~= "^\d+$" && image.2 ~= "^\d+$" && image.3 ~= "^\d+$" && image.4 ~= "^\d+$") {
pBitmap := Gdip_BitmapFromScreen(image.1 "|" image.2 "|" image.3 "|" image.4)
Gdip_SaveBitmapToFile(pBitmap, outputFile)
Gdip_DisposeImage(pBitmap)
}
; Check if image points to a valid file
else if FileExist(image) {
Loop, Files, % image
{
if (A_LoopFileExt != "bmp" || IsObject(crop)) {
pBitmap := Gdip_CreateBitmapFromFile(A_LoopFileLongPath)
(crop) ? Vis2.stdlib.Gdip_CropBitmap(pBitmap, crop) : ""
Gdip_SaveBitmapToFile(pBitmap, outputFile)
Gdip_DisposeImage(pBitmap)
}
else outputFile := A_LoopFileLongPath
}
}
; Check if image points to a valid URL
else if Vis2.stdlib.isURL(image) {
static 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, "uptr*",pBitmap)
(crop) ? Vis2.stdlib.Gdip_CropBitmap(pBitmap, crop) : ""
Gdip_SaveBitmapToFile(pBitmap, outputFile, 92)
ObjRelease(pStream)
Gdip_DisposeImage(pBitmap)
}
; Check if image matches a window title OR is a valid handle to a window
else if (DllCall("IsWindow", "ptr",image) || (hwnd := WinExist(image))) {
hwnd := (DllCall("IsWindow", "ptr",image)) ? image : hwnd
pBitmap := Vis2.stdlib.Gdip_BitmapFromClientHWND(hwnd)
(crop) ? Vis2.stdlib.Gdip_CropBitmap(pBitmap, crop) : ""
Gdip_SaveBitmapToFile(pBitmap, outputFile)
Gdip_DisposeImage(pBitmap)
}
; Check if image is a valid GDI Bitmap
else if DeleteObject(Gdip_CreateHBITMAPFromBitmap(image)) {
(crop) ? Vis2.stdlib.Gdip_CropBitmap(image, crop, true) : ""
Gdip_SaveBitmapToFile(image, outputFile)
}
; Check if image is a valid handle to a GDI Bitmap
else if (DllCall("GetObjectType", "ptr",image) == 7) {
pBitmap := Gdip_CreateBitmapFromHBITMAP(image)
(crop) ? Vis2.stdlib.Gdip_CropBitmap(pBitmap, crop) : ""
Gdip_SaveBitmapToFile(pBitmap, outputFile)
Gdip_DisposeImage(pBitmap)
}
; Check if image is a base64 string
else if (image ~= "^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$") {
nSize := Vis2.stdlib.b64Decode(image, bin)
hData := DllCall("GlobalAlloc", "uint",0x2, "ptr",nSize)
pData := DllCall("GlobalLock", "ptr",hData)
DllCall("RtlMoveMemory", "ptr",pData, "ptr",&bin, "ptr",nSize)
DllCall("GlobalUnlock", "ptr",hData)
DllCall("ole32\CreateStreamOnHGlobal", "ptr",hData, "int",1, "uptr*",pStream)
DllCall("gdiplus\GdipCreateBitmapFromStream", "ptr",pStream, "uptr*",pBitmap)
(crop) ? Vis2.stdlib.Gdip_CropBitmap(pBitmap, crop) : ""
Gdip_SaveBitmapToFile(pBitmap, outputFile, 92)
DllCall(NumGet(NumGet(pStream + 0, 0, "uptr") + (A_PtrSize * 2), 0, "uptr"), "ptr",pStream)
DllCall("GlobalFree", "ptr",hData)
ObjRelease(pStream)
Gdip_DisposeImage(pBitmap)
}
if !(FileExist(outputFile))
throw Exception("Could not find source image.")
Vis2.Graphics.Shutdown()
return outputFile
}
}
}