Тема: AHK: Сохранить скриншот в файл
Можно каким-то простым способом сохранить скриншот в файл?
Например получаем его в буфер обмена Send !{PRINTSCREEN} и далее содержимое буфера сохранить в файл например C:\file.png
Вы не вошли. Пожалуйста, войдите или зарегистрируйтесь.
Страницы 1
Чтобы отправить ответ, вы должны войти или зарегистрироваться
Можно каким-то простым способом сохранить скриншот в файл?
Например получаем его в буфер обмена Send !{PRINTSCREEN} и далее содержимое буфера сохранить в файл например C:\file.png
Например, так можно (PrintScreen не нужен):
SaveScreenshotToFile(0, 0, A_ScreenWidth, A_ScreenHeight, A_ScriptDir . "\test.png")
;Run, % A_ScriptDir . "\test.png"
SaveScreenshotToFile(x, y, w, h, filePath) {
hBitmap := GetHBitmapFromScreen(x, y, w, h)
gdip := new GDIplus
pBitmap := gdip.BitmapFromHBitmap(hBitmap)
DllCall("DeleteObject", Ptr, hBitmap)
gdip.SaveBitmapToFile(pBitmap, filePath)
gdip.DisposeImage(pBitmap)
}
GetHBitmapFromScreen(x, y, w, h) {
hDC := DllCall("GetDC", Ptr, 0, Ptr)
hBM := DllCall("CreateCompatibleBitmap", Ptr, hDC, Int, w, Int, h, Ptr)
pDC := DllCall("CreateCompatibleDC", Ptr, hDC, Ptr)
oBM := DllCall("SelectObject", Ptr, pDC, Ptr, hBM, Ptr)
DllCall("BitBlt", Ptr, pDC, Int, 0, Int, 0, Int, w, Int, h, Ptr, hDC, Int, x, Int, y, UInt, 0x00CC0020)
DllCall("SelectObject", Ptr, pDC, Ptr, oBM)
DllCall("DeleteDC", Ptr, pDC)
DllCall("ReleaseDC", Ptr, 0, Ptr, hDC)
Return hBM ; should be deleted with DllCall("DeleteObject", Ptr, hBM)
}
class GDIplus {
__New() {
if !DllCall("GetModuleHandle", Str, "gdiplus", Ptr)
DllCall("LoadLibrary", Str, "gdiplus")
VarSetCapacity(si, A_PtrSize = 8 ? 24 : 16, 0), si := Chr(1)
DllCall("gdiplus\GdiplusStartup", PtrP, pToken, Ptr, &si, Ptr, 0)
this.token := pToken
}
__Delete() {
DllCall("gdiplus\GdiplusShutdown", Ptr, this.token)
if hModule := DllCall("GetModuleHandle", Str, "gdiplus", Ptr)
DllCall("FreeLibrary", Ptr, hModule)
}
BitmapFromHBitmap(hBitmap, Palette := 0) {
DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", Ptr, hBitmap, Ptr, Palette, PtrP, pBitmap)
return pBitmap ; should be deleted with this.DisposeImage(pBitmap)
}
SaveBitmapToFile(pBitmap, sOutput, Quality=75) {
SplitPath, sOutput,,, Extension
if Extension not in BMP,DIB,RLE,JPG,JPEG,JPE,JFIF,GIF,TIF,TIFF,PNG
return -1
DllCall("gdiplus\GdipGetImageEncodersSize", UIntP, nCount, UIntP, 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 RegExMatch(Extension, "i)^J(PG|PEG|PE|FIF)$") && Quality != 75 {
DllCall("gdiplus\GdipGetEncoderParameterListSize", Ptr, pBitmap, Ptr, pCodec, UintP, 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_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
}
}
}
if A_IsUnicode
pOutput := &sOutput
else {
VarSetCapacity(wOutput, StrPut(sOutput, "UTF-16")*2, 0)
StrPut(sOutput, &wOutput, "UTF-16")
pOutput := &wOutput
}
E := DllCall("gdiplus\GdipSaveImageToFile", Ptr, pBitmap, Ptr, pOutput, Ptr, pCodec, UInt, p ? p : 0)
return E ? -5 : 0
}
DisposeImage(pBitmap) {
return DllCall("gdiplus\GdipDisposeImage", Ptr, pBitmap)
}
}Вариант, что я сейчас привёл, самый простой, не требует никаких библиотек.
Думал, хотя бы «спасибо» скажут. ![]()
Оставь надежду, всяк сюда входящий. (с)
По идее, ThrowSum должен оправдать свой ник и какую-нибудь сумму тебе бросить. Наверно, твоё алчное подсознание за это и зацепилось. ![]()
Вряд ли моё подсознание расценило этот ник, как обещание, тут скорее призыв или крик о помощи.
А можешь опционально добавить сохранение с курсором мыши.
Странное какое-то обсуждение в нижней части, скажу так что у меня было день рождение, ну и проверить все варианты я как бы не смог, отписаться я решил чуть позже после тестов.
Итак, teadrinker огромное спасибо, вы мне и в прошлые разы помогали. Ссылки которые дал уважаемый ypppu, я смотрел еще до старта темы пользуясь поиском по форуму, за это тоже благодарен, но все решения показались мне громоздкими, я надеялся что скрин можно сохранить парой строк понимая что они делают.
Например, так можно (PrintScreen не нужен)
А спросить я хотел по поводу этого скрипта, я поставил его просто на хоткей и он отлично сохраняет скрины, можно и таймштампы поставить в названии файла и размеры скриншота задать. Только вот образовалась такая проблема: в одном моём цикле делается 2 скриншота, до и после. Цикла всего 3. А проблема вот в чем:
делается скрин 1 - сохраненная картинка по-моему от предыдущего теста
скрин 2 - картинка сохранена со данными скрина 1
И так далее со сдвигом в единицу. Создается ощущение, что там где должна быть сохранена картинка 2, берется из кэша картинка 1 и сохраняется. Вот причину этого я пока не понял, возможно у меня в коде проблемы, хотя там простые циклы из которых вызывается функция SaveScreenshotToFile.
можно и таймштампы поставить
teadrinker
Кстати, ещё бы опционально добавление текста в указанный угол или центр картинки, и в коллекцию.
А можешь опционально добавить сохранение с курсором мыши.
; SaveScreenshotToFile(A_ScriptDir . "\test.png", [0, 0, A_ScreenWidth, A_ScreenHeight], true)
SaveScreenshotToFile(A_ScriptDir . "\test.png")
Run, % A_ScriptDir . "\test.png"
SaveScreenshotToFile(filePath, oCoords := "", captureCursor := false) {
/*
oCoords — массив координат области экрана вида [x, y, w, h], например:
[0, 0, A_ScreenWidth, A_ScreenHeight] или [300, 300, 500, 500]
если массив пустой либо один из элементов пустой или не число — будет сделан скриншот всего виртуального экрана
captureCursor — если true, курсор будет включён в скриншот
*/
for k, v in ["x", "y", "w", "h"]
if ( (%v% := oCoords[k]) + 0 = "" && empty := true )
break
if empty {
Sysget, x, 76
Sysget, y, 77
Sysget, w, 78
Sysget, h, 79
}
hBitmap := GetHBitmapFromScreen(x, y, w, h, captureCursor)
gdip := new GDIplus
pBitmap := gdip.BitmapFromHBitmap(hBitmap)
DllCall("DeleteObject", Ptr, hBitmap)
gdip.SaveBitmapToFile(pBitmap, filePath)
gdip.DisposeImage(pBitmap)
}
GetHBitmapFromScreen(x, y, w, h, captureCursor) {
hDC := DllCall("GetDC", Ptr, 0, Ptr)
hBM := DllCall("CreateCompatibleBitmap", Ptr, hDC, Int, w, Int, h, Ptr)
hMDC := DllCall("CreateCompatibleDC", Ptr, hDC, Ptr)
oBM := DllCall("SelectObject", Ptr, hMDC, Ptr, hBM, Ptr)
DllCall("BitBlt", Ptr, hMDC, Int, 0, Int, 0, Int, w, Int, h, Ptr, hDC, Int, x, Int, y, UInt, 0x00CC0020)
( captureCursor && CaptureCursor(hMDC, x, y) )
DllCall("SelectObject", Ptr, hMDC, Ptr, oBM)
DllCall("DeleteDC", Ptr, hMDC)
DllCall("ReleaseDC", Ptr, 0, Ptr, hDC)
Return hBM ; should be deleted with DllCall("DeleteObject", Ptr, hBM)
}
CaptureCursor(hDC, x, y) {
VarSetCapacity(CURSORINFO, szCI := 4*2 + A_PtrSize + 8, 0)
NumPut(szCI, CURSORINFO)
DllCall("GetCursorInfo", Ptr, &CURSORINFO)
bShow := NumGet(CURSORINFO, 4, "UInt")
hCursor := NumGet(CURSORINFO, 4*2)
xCursor := NumGet(CURSORINFO, 4*2 + A_PtrSize, "Int")
yCursor := NumGet(CURSORINFO, 4*2 + A_PtrSize + 4, "Int")
if bShow && hCursor := DllCall("CopyIcon", Ptr, hCursor, Ptr) {
VarSetCapacity(ICONINFO, 4*2 + A_PtrSize*3, 0)
DllCall("GetIconInfo", Ptr, hCursor, Ptr, &ICONINFO)
bIcon := NumGet(ICONINFO, "UInt")
xHotspot := NumGet(ICONINFO, 4, "UInt")
yHotspot := NumGet(ICONINFO, 4*2, "UInt")
hBMMask := NumGet(ICONINFO, 4*2 + A_PtrSize)
hBMColor := NumGet(ICONINFO, 4*2 + A_PtrSize*2)
DllCall("DrawIcon", Ptr, hDC, Int, xCursor - xHotspot - x, Int, yCursor - yHotspot - y, Ptr, hCursor)
DllCall("DestroyIcon", Ptr, hCursor)
( hBMMask && DllCall("DeleteObject", Ptr, hBMMask) )
( hBMColor && DllCall("DeleteObject", Ptr, hBMColor) )
}
}
class GDIplus {
__New() {
if !DllCall("GetModuleHandle", Str, "gdiplus", Ptr)
DllCall("LoadLibrary", Str, "gdiplus")
VarSetCapacity(si, A_PtrSize = 8 ? 24 : 16, 0), si := Chr(1)
DllCall("gdiplus\GdiplusStartup", PtrP, pToken, Ptr, &si, Ptr, 0)
this.token := pToken
}
__Delete() {
DllCall("gdiplus\GdiplusShutdown", Ptr, this.token)
if hModule := DllCall("GetModuleHandle", Str, "gdiplus", Ptr)
DllCall("FreeLibrary", Ptr, hModule)
}
BitmapFromHBitmap(hBitmap, Palette := 0) {
DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", Ptr, hBitmap, Ptr, Palette, PtrP, pBitmap)
return pBitmap ; should be deleted with this.DisposeImage(pBitmap)
}
SaveBitmapToFile(pBitmap, sOutput, Quality=75) {
SplitPath, sOutput,,, Extension
if Extension not in BMP,DIB,RLE,JPG,JPEG,JPE,JFIF,GIF,TIF,TIFF,PNG
return -1
DllCall("gdiplus\GdipGetImageEncodersSize", UIntP, nCount, UIntP, 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 RegExMatch(Extension, "i)^J(PG|PEG|PE|FIF)$") && Quality != 75 {
DllCall("gdiplus\GdipGetEncoderParameterListSize", Ptr, pBitmap, Ptr, pCodec, UintP, 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_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
}
}
}
if A_IsUnicode
pOutput := &sOutput
else {
VarSetCapacity(wOutput, StrPut(sOutput, "UTF-16")*2, 0)
StrPut(sOutput, &wOutput, "UTF-16")
pOutput := &wOutput
}
E := DllCall("gdiplus\GdipSaveImageToFile", Ptr, pBitmap, Ptr, pOutput, Ptr, pCodec, UInt, p ? p : 0)
return E ? -5 : 0
}
DisposeImage(pBitmap) {
return DllCall("gdiplus\GdipDisposeImage", Ptr, pBitmap)
}
}Кстати, ещё бы опционально добавление текста в указанный угол или центр картинки, и в коллекцию.
Это уже выходит за рамки простой функции. Тут тогда придётся принимать в качестве параметров все свойства текста — шрифт, размер, написание, жирность, цвет, перенос, выравнивание.
ThrowSum, нужен пример кода, как вызываете функцию.
Это уже выходит за рамки простой функции
А за чем простая функция, главное функциональная. Параметры текста в массиве передавать, там же и его местоположение. Оно и нужно, потому что непросто.
Ну так-то можно много всяких добавлений и усложнений придумать.
Например, добавить своё изображение в скриншот, изменить размер всего изображения (пропорционально или непропорционально), сделать какой-либо цвет прозрачным или ещё что угодно. Но это уже не скриншот будет, это просто выходит за рамки указанной темы.
Можно сделать так: добавить ещё один параметр "userFunc" со ссылкой на пользовательскую функцию, которая перед сохранением будет как-то изменять итоговый hMDC, как сейчас это делает CaptureCursor().
Я себе может что и состряпаю если понадобится, но речь про новичков. Добавить текст в картинку для них задача нетривиальная, а зачастую им не то что функции, а параметры добавить сложно. Автоматическое добавление даты и ещё какой инфы на скриншот, помоему дело распространённое. Чтобы стрелки добавлять, файл можно после сохранения открывать в редакторе по умолчанию, до этого большинство само допетрит, и по другому это всё равно никак не сделать. Насчёт показа в гуи, можно вместо пути указать звёздочку, чтобы битмап возращало.
Думаю такая функция не помешает в коллекции и тем кто может это сделать сам, для того она и есть чтобы не писать самому, а брать готовое. Ну а если сделать заливку на хостинг, то вообще мастхэв.
С текстом завтра попробую, а с заливкой на хостинг у меня уже есть основной скриншотный скрипт, который всё никак выложить не могу. Но там сложность есть — регистрироваться нужно и получать что-то типа id.
ThrowSum, нужен пример кода, как вызываете функцию.
Поставил больший Sleep перед и после функции, теперь работает, возможно из-за этого проблема была.
С текстом так вышло:
oRect := [ 100, 100, A_ScreenWidth - 200, A_ScreenHeight - 200 ]
oText := { fontFamily: "Verdana"
, fontOptions: "cBlue s10 bold q5"
, textOptions: "x" . A_ScreenWidth - 250 . " y40 right"
, text: "Серый Форум ©`nAll rights reserved`n" . A_Year . "." . A_MM . "." . A_DD }
SaveScreenshotToFile(A_ScriptDir . "\test.png", oRect, true, oText)
Run, % A_ScriptDir . "\test.png"
ExitApp
SaveScreenshotToFile(filePath, oRect := "", captureCursor := false, oText := "") {
/*
oRect — массив координат области экрана вида [x, y, w, h], например:
[0, 0, A_ScreenWidth, A_ScreenHeight] или [300, 300, 500, 500]
если массив пустой либо один из элементов пустой или не число — будет сделан скриншот всего виртуального экрана
captureCursor — если true, курсор будет включён в скриншот
oText — объект вида:
{ fontFamily: "calibri"
, fontOptions: "cRed s24 w800 italic q5" ; как в команде Gui, Font
, textOptions: "x10 y10 w200 center" ; как в команде Gui, Add, Text
; x и y отсчитываются от левого верхнего края скриншота (не экрана)
; w нужно, если указано right или center, если w не указано, считается равным 0; h не нужно
; если указано right и текст не помещается по ширине w, он будет сдвинут влево
, text: "Создано:`n01.12.2017" }
*/
for k, v in ["x", "y", "w", "h"]
if ( (%v% := oRect[k]) + 0 = "" && empty := true )
break
if empty {
Sysget, x, 76
Sysget, y, 77
Sysget, w, 78
Sysget, h, 79
}
hBitmap := GetHBitmapFromScreen(x, y, w, h, captureCursor, oText)
gdip := new GDIplus
pBitmap := gdip.BitmapFromHBitmap(hBitmap)
DllCall("DeleteObject", Ptr, hBitmap)
gdip.SaveBitmapToFile(pBitmap, filePath)
gdip.DisposeImage(pBitmap)
}
GetHBitmapFromScreen(x, y, w, h, captureCursor, oText) {
hDC := DllCall("GetDC", Ptr, 0, Ptr)
hBM := DllCall("CreateCompatibleBitmap", Ptr, hDC, Int, w, Int, h, Ptr)
hMDC := DllCall("CreateCompatibleDC", Ptr, hDC, Ptr)
oBM := DllCall("SelectObject", Ptr, hMDC, Ptr, hBM, Ptr)
DllCall("BitBlt", Ptr, hMDC, Int, 0, Int, 0, Int, w, Int, h, Ptr, hDC, Int, x, Int, y, UInt, 0x00CC0020)
( captureCursor && CaptureCursor(hMDC, x, y) )
( IsObject(oText) && DrawText(hMDC, oText) )
DllCall("SelectObject", Ptr, hMDC, Ptr, oBM)
DllCall("DeleteDC", Ptr, hMDC)
DllCall("ReleaseDC", Ptr, 0, Ptr, hDC)
Return hBM ; should be deleted with DllCall("DeleteObject", Ptr, hBM)
}
CaptureCursor(hDC, x, y) {
VarSetCapacity(CURSORINFO, szCI := 4*2 + A_PtrSize + 8, 0)
NumPut(szCI, CURSORINFO)
DllCall("GetCursorInfo", Ptr, &CURSORINFO)
bShow := NumGet(CURSORINFO, 4, "UInt")
hCursor := NumGet(CURSORINFO, 4*2)
xCursor := NumGet(CURSORINFO, 4*2 + A_PtrSize, "Int")
yCursor := NumGet(CURSORINFO, 4*2 + A_PtrSize + 4, "Int")
if bShow && hCursor := DllCall("CopyIcon", Ptr, hCursor, Ptr) {
VarSetCapacity(ICONINFO, 4*2 + A_PtrSize*3, 0)
DllCall("GetIconInfo", Ptr, hCursor, Ptr, &ICONINFO)
bIcon := NumGet(ICONINFO, "UInt")
xHotspot := NumGet(ICONINFO, 4, "UInt")
yHotspot := NumGet(ICONINFO, 4*2, "UInt")
hBMMask := NumGet(ICONINFO, 4*2 + A_PtrSize)
hBMColor := NumGet(ICONINFO, 4*2 + A_PtrSize*2)
DllCall("DrawIcon", Ptr, hDC, Int, xCursor - xHotspot - x, Int, yCursor - yHotspot - y, Ptr, hCursor)
DllCall("DestroyIcon", Ptr, hCursor)
( hBMMask && DllCall("DeleteObject", Ptr, hBMMask) )
( hBMColor && DllCall("DeleteObject", Ptr, hBMColor) )
}
}
DrawText(hDC, options) {
static WM_CTLCOLORSTATIC := 0x138, WM_GETFONT := 0x31, TRANSPARENT := 1
, DT_NOCLIP := 0x100, DT_CENTER := 0x1, DT_RIGHT := 0x2, DT_LEFT := 0
Gui, New, +hwndhGui
Gui, Font, % options.fontOptions, % options.fontFamily
Gui, Add, Text, % options.textOptions . " hwndhText", % options.text
hTextDC := DllCall("GetDC", Ptr, hText, Ptr)
DllCall("SendMessage", Ptr, hGui, UInt, WM_CTLCOLORSTATIC, Ptr, hTextDC, Ptr, hText)
clr := DllCall("GetTextColor", Ptr, hTextDC)
DllCall("ReleaseDC", Ptr, 0, Ptr, hTextDC)
hFont := DllCall("SendMessage", Ptr, hText, UInt, WM_GETFONT, Ptr, 0, Ptr, 0, Ptr)
Gui, Destroy
obj := DllCall("SelectObject", Ptr, hDC, Ptr, hFont, Ptr)
DllCall("SetBkMode", Ptr, hDC, Int, TRANSPARENT)
DllCall("SetTextColor", Ptr, hDC, UInt, clr)
RegExMatch(options.textOptions, "i)(^|\s)\Kx(?<X>\d+)", text)
RegExMatch(options.textOptions, "i)(^|\s)\Ky(?<Y>\d+)", text)
RegExMatch(options.textOptions, "i)(^|\s)\Kw(?<W>\d+)", text)
left := textX = "" ? 0 : textX
top := textY = "" ? 0 : textY
right := textW = "" ? left : left + textW
VarSetCapacity(RECT, 16, 0)
NumPut(left , RECT, 0)
NumPut(top , RECT, 4)
NumPut(right , RECT, 8)
RegExMatch(options.textOptions, "i)(^|\s)\K(?<Align>right|center)", text)
align := {right: DT_RIGHT, center: DT_CENTER, "": DT_LEFT}[textAlign]
DllCall("DrawText", Ptr, hDC, Str, options.text, Int, -1, Ptr, &RECT, UInt, DT_NOCLIP|align)
DllCall("SelectObject", Ptr, hDC, Ptr, obj, Ptr)
DllCall("DeleteObject", Ptr, hFont)
}
class GDIplus {
__New() {
if !DllCall("GetModuleHandle", Str, "gdiplus", Ptr)
DllCall("LoadLibrary", Str, "gdiplus")
VarSetCapacity(si, A_PtrSize = 8 ? 24 : 16, 0), si := Chr(1)
DllCall("gdiplus\GdiplusStartup", PtrP, pToken, Ptr, &si, Ptr, 0)
this.token := pToken
}
__Delete() {
DllCall("gdiplus\GdiplusShutdown", Ptr, this.token)
if hModule := DllCall("GetModuleHandle", Str, "gdiplus", Ptr)
DllCall("FreeLibrary", Ptr, hModule)
}
BitmapFromHBitmap(hBitmap, Palette := 0) {
DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", Ptr, hBitmap, Ptr, Palette, PtrP, pBitmap)
return pBitmap ; should be deleted with this.DisposeImage(pBitmap)
}
SaveBitmapToFile(pBitmap, sOutput, Quality=75) {
SplitPath, sOutput,,, Extension
if Extension not in BMP,DIB,RLE,JPG,JPEG,JPE,JFIF,GIF,TIF,TIFF,PNG
return -1
DllCall("gdiplus\GdipGetImageEncodersSize", UIntP, nCount, UIntP, 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 RegExMatch(Extension, "i)^J(PG|PEG|PE|FIF)$") && Quality != 75 {
DllCall("gdiplus\GdipGetEncoderParameterListSize", Ptr, pBitmap, Ptr, pCodec, UintP, 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_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
}
}
}
if A_IsUnicode
pOutput := &sOutput
else {
VarSetCapacity(wOutput, StrPut(sOutput, "UTF-16")*2, 0)
StrPut(sOutput, &wOutput, "UTF-16")
pOutput := &wOutput
}
E := DllCall("gdiplus\GdipSaveImageToFile", Ptr, pBitmap, Ptr, pOutput, Ptr, pCodec, UInt, p ? p : 0)
return E ? -5 : 0
}
DisposeImage(pBitmap) {
return DllCall("gdiplus\GdipDisposeImage", Ptr, pBitmap)
}
}С текстом завтра попробую, а с заливкой на хостинг у меня уже есть основной скриншотный скрипт, который всё никак выложить не могу. Но там сложность есть — регистрироваться нужно и получать что-то типа id.
Ты не про imgur.com? Не пойму как там API token получить.
Регистрируешься на сайте, переходишь по ссылке, указываешь имя приложения (любое), выбираешь "OAuth 2 autorization without callback url", указываешь email. Получаешь Client ID и Client Secret. Последний уже не помню для чего нужен, в приложении используется Client ID.
Спасибо, код отсюда заработал!
Можешь выложить свой код по теме imgur API, по ссылке только х32.
Или как bitmap преобразовать в binarydata.
Только руки дошли:
SetWorkingDir, %A_ScriptDir%
SetBatchLines, -1
if !FileExist("AHK.png")
URLDownloadToFile, https://autohotkey.com/assets/images/ahk-logo-no-text241x78-180.png, AHK.png
ClientID := "1234abcde5678fg" ; указать свой ClientID
imagePath := "AHK.png" ; указать путь к изображению
SendImageToImgur(imagePath, ClientID)
Return
SendImageToImgur(imagePath, ClientID, JpegQuality := "") {
oGdi := new GDIp
hBitmap := LoadPicture(imagePath, "GDI+")
pBitmap := oGdi.CreateBitmapFromHBITMAP(hBitmap)
SplitPath, imagePath,,, ext
buff := ext
if ( (size := oGdi.SaveBitmap(pBitmap, buff, JpegQuality, true)) < 0 ) {
Errors := { 2: "Could not get a list of encoders on system"
, 3: "Could not find matching encoder for specified file format"
, 4: "Could not save the bitmap to buffer" }
MsgBox, 48, Ошибка записи в буфер, % Errors[-size]
Return
}
DllCall("DeleteObject", Ptr, hBitmap)
oGdi.DisposeImage(pBitmap)
strBase64 := CryptBinaryToStringBASE64(&buff, size, true)
http := ComObjCreate("Msxml2.XMLHTTP")
http.open("POST", "https://api.imgur.com/3/image", true)
http.onreadystatechange := Func("StateChange").Bind(http)
http.SetRequestHeader("authorization", "Client-ID " . ClientID)
http.send(strBase64)
VarSetCapacity(strBase64, 0), VarSetCapacity(buff, 0)
}
StateChange(http) {
if !(http.readyState = 4)
Return
responsetext := http.responsetext
if (http.status != 200) {
MsgBox, % "Ошибка отправки файла на imgur.com! Status: " . http.status . "`nResponsetext: " . responsetext
Return
}
RegExMatch(responsetext, """link"":""(.*?)""", match)
link := StrReplace(match1, "\")
Gui, Imgur: Default
try Gui, Destroy
Gui, Font, s9
Gui, Add, Edit, % "w250 h" . (link ? 24 : 120), % link ? link : responsetext
Gui, Font
Gui, Add, Button, x+-80 y+7 w80 h24 gCopyResponse Default, Copy
GuiControl, Focus, Button1
Gui, Show,, Imgur.com
}
CopyResponse() {
GuiControlGet, Clipboard, Imgur:, Edit1
Gui, Imgur: Destroy
}
CryptBinaryToStringBASE64(pData, Bytes, NOCRLF = "") {
static CRYPT_STRING_BASE64 := 1, CRYPT_STRING_NOCRLF := 0x40000000
CRYPT := CRYPT_STRING_BASE64 | (NOCRLF ? CRYPT_STRING_NOCRLF : 0)
DllCall("Crypt32\CryptBinaryToString", Ptr, pData, UInt, Bytes, UInt, CRYPT, Ptr, 0, UIntP, Chars)
VarSetCapacity(OutData, Chars * (A_IsUnicode ? 2 : 1))
DllCall("Crypt32\CryptBinaryToString", Ptr, pData, UInt, Bytes, UInt, CRYPT, Str, OutData, UIntP, Chars)
Return OutData
}
class GDIp {
__New() {
if !DllCall("GetModuleHandle", Str, "gdiplus", Ptr)
DllCall("LoadLibrary", Str, "gdiplus")
VarSetCapacity(si, A_PtrSize = 8 ? 24 : 16, 0), si := Chr(1)
DllCall("gdiplus\GdiplusStartup", UPtrP, pToken, Ptr, &si, Ptr, 0)
this.token := pToken
}
__Delete() {
DllCall("gdiplus\GdiplusShutdown", Ptr, this.token)
if hModule := DllCall("GetModuleHandle", Str, "gdiplus", Ptr)
DllCall("FreeLibrary", Ptr, hModule)
}
CreateBitmapFromHBITMAP(hBitmap, Palette=0) {
DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", Ptr, hBitmap, Ptr, Palette, PtrP, pBitmap)
return pBitmap
}
SaveBitmap(pBitmap, ByRef info, Quality := 75, tobuff := "")
{
; info — если копируем в буфер, тогда расширение файла, если в файл, тогда путь к файлу
if tobuff
Extension := info
else
SplitPath, info,,, Extension
if Extension not in BMP,DIB,RLE,JPG,JPEG,JPE,JFIF,GIF,TIF,TIFF,PNG
return -1
DllCall("gdiplus\GdipGetImageEncodersSize", UintP, nCount, UintP, 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 RegExMatch(Extension, "i)^J(PG|PEG|PE|FIF)$") && Quality != 75 {
DllCall("gdiplus\GdipGetEncoderParameterListSize", Ptr, pBitmap, Ptr, pCodec, UintP, 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_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
}
}
}
if !tobuff
E := DllCall("gdiplus\GdipSaveImageToFile", Ptr, pBitmap, WStr, info, Ptr, pCodec, UInt, p ? p : 0)
else {
DllCall( "ole32\CreateStreamOnHGlobal", UInt, 0, Int, 1, PtrP, pStream )
if !E := DllCall( "gdiplus\GdipSaveImageToStream", Ptr, pBitmap, Ptr, pStream, Ptr, pCodec, UInt, p ? p : 0 ) {
DllCall( "ole32\GetHGlobalFromStream", Ptr, pStream, PtrP, hData )
pData := DllCall( "GlobalLock", Ptr, hData, Ptr )
nSize := DllCall( "GlobalSize", Ptr, hData, Ptr )
VarSetCapacity( info, 0), VarSetCapacity( info, nSize, 0 )
DllCall( "RtlMoveMemory", Ptr, &info, Ptr, pData, UInt, nSize )
DllCall( "GlobalUnlock", Ptr, hData )
DllCall( "GlobalFree", Ptr, hData )
}
ObjRelease(pStream)
}
return E ? -4 : tobuff ? nSize : 0
}
DisposeImage(pBitmap) {
return DllCall("gdiplus\GdipDisposeImage", Ptr, pBitmap)
}
}Нужно указать свой Client ID, в коде неверный.
Оказалось, перемудрил маленько, всё проще:
#NoEnv
SetBatchLines, -1
if (!imagePath := A_Args[1])
FileSelectFile, imagePath,,, Выберите файл изображения для загрузки на imgur.com, Images (*.png; *.bmp; *.tiff; *.tif; *.jpeg; *.jpg; *.gif)
if !imagePath
ExitApp
SendImageToImgur(imagePath, ClientID := "1234abcd5678ef")
Return
ImgurGuiClose:
ExitApp
SendImageToImgur(imagePath, ClientID, JpegQuality := "") {
oFile := FileOpen(imagePath, "r")
oFile.Pos := 0
oFile.RawRead(buff, size := oFile.length)
oFile.Close()
strBase64 := CryptBinaryToStringBASE64(&buff, size, true)
http := ComObjCreate("Msxml2.XMLHTTP")
http.open("POST", "https://api.imgur.com/3/image", true)
http.onreadystatechange := Func("StateChange").Bind(http)
http.SetRequestHeader("authorization", "Client-ID " . ClientID)
http.send(strBase64)
VarSetCapacity(strBase64, 0), VarSetCapacity(buff, 0)
}
StateChange(http) {
if !(http.readyState = 4)
Return
responsetext := http.responsetext
if (http.status != 200) {
MsgBox, % "Ошибка отправки файла на imgur.com! Status: " . http.status . "`nResponsetext: " . responsetext
ExitApp
}
RegExMatch(responsetext, """link"":""(.*?)""", match)
link := StrReplace(match1, "\")
Gui, Imgur: Default
Gui, Font, s9
Gui, Add, Edit, % "w250 h" . (link ? 24 : 120), % link ? link : responsetext
Gui, Font
Gui, Add, Button, x+-80 y+7 w80 h24 gCopyResponse Default, Copy
GuiControl, Focus, Button1
Gui, Show,, Imgur.com
}
CopyResponse() {
GuiControlGet, Clipboard, Imgur:, Edit1
Gui, Imgur: Destroy
ExitApp
}
CryptBinaryToStringBASE64(pData, Bytes, NOCRLF = "") {
static CRYPT_STRING_BASE64 := 1, CRYPT_STRING_NOCRLF := 0x40000000
CRYPT := CRYPT_STRING_BASE64 | (NOCRLF ? CRYPT_STRING_NOCRLF : 0)
DllCall("Crypt32\CryptBinaryToString", Ptr, pData, UInt, Bytes, UInt, CRYPT, Ptr, 0, UIntP, Chars)
VarSetCapacity(OutData, Chars * (A_IsUnicode ? 2 : 1))
DllCall("Crypt32\CryptBinaryToString", Ptr, pData, UInt, Bytes, UInt, CRYPT, Str, OutData, UIntP, Chars)
Return OutData
}А вариант со скриншотом можешь заодно запилить, чтобы без файла.
teadrinker
а есть вариант, чтобы файл автоматически сам выбирался?
Где выбирался?
teadrinker
В директории, допустим я укажу где лежит файл C:/User/sobaka.png и он его сам выберет
Не совсем понял идею, хотите указать папку, и загрузить из неё все файлы изображений? Если не все, а один, то по какому признаку выбирать?
teadrinker
ну вот у Вас в коде:
if (!imagePath := A_Args[1])
FileSelectFile, imagePath,,, Выберите файл изображения для загрузки на imgur.com, Images (*.png; *.bmp; *.tiff; *.tif; *.jpeg; *.jpg; *.gif)Вот мне нужно, чтоб не выбирать файл в окне, а он сам выбирался автоматически по его местоположению (допустим файл в C:/Pictures/kartinka.png) и он его выбирает сам, без диалоговых окон.
Пропишите вместо этого нужный файл в переменную imagePath.
teadrinker
спасибо большое!
А вариант со скриншотом можешь заодно запилить, чтобы без файла.
SetBatchLines, -1
ClientID := "7a203d761ce36c4" ; указать свой ClientID, здесь недействительный
SendScreenshotToImgur(ClientID, [0, 0, 200, 200])
Return
SendScreenshotToImgur(ClientID, oCoords := "", ext := "png", captureCursor := false, jpegQuality := 75) {
/*
oCoords — массив координат области экрана вида [x, y, w, h], например:
[0, 0, A_ScreenWidth, A_ScreenHeight] или [300, 300, 500, 500]
если массив пустой либо один из элементов пустой или не число — будет сделан скриншот всего виртуального экрана
ext — указать расширение файла, в формате которого будет загружено изображение
captureCursor — если true, курсор будет включён в скриншот
jpegQuality — указать качество, если указано расширение jpeg
*/
for k, v in ["x", "y", "w", "h"]
if ( (%v% := oCoords[k]) + 0 = "" && empty := true )
break
if empty {
Sysget, x, 76
Sysget, y, 77
Sysget, w, 78
Sysget, h, 79
}
hBitmap := GetHBitmapFromScreen(x, y, w, h, captureCursor)
gdip := new GDIplus
pBitmap := gdip.BitmapFromHBitmap(hBitmap)
DllCall("DeleteObject", Ptr, hBitmap)
buff := ext
if ( (size := gdip.SaveBitmap(pBitmap, buff, jpegQuality, true)) < 0 ) {
Errors := { 1: "Extention " . ext . " doesn't supported. Supported extentions:`nBMP,DIB,RLE,JPG,JPEG,JPE,JFIF,GIF,TIF,TIFF,PNG"
, 2: "Could not get a list of encoders on system"
, 3: "Could not find matching encoder for specified file format"
, 4: "Could not save the bitmap to buffer" }
MsgBox, 48, Ошибка записи в буфер, % Errors[-size]
Return
}
gdip.DisposeImage(pBitmap)
strBase64 := CryptBinaryToStringBASE64(&buff, size, true)
http := ComObjCreate("Msxml2.XMLHTTP")
http.open("POST", "https://api.imgur.com/3/image", true)
http.onreadystatechange := Func("StateChange").Bind(http)
http.SetRequestHeader("authorization", "Client-ID " . ClientID)
http.send(strBase64)
VarSetCapacity(strBase64, 0), VarSetCapacity(buff, 0)
}
StateChange(http) {
if !(http.readyState = 4)
Return
responsetext := http.responsetext
if (http.status != 200) {
MsgBox, % "Ошибка отправки файла на imgur.com! Status: " . http.status . "`nResponsetext: " . responsetext
ExitApp
}
RegExMatch(responsetext, """link"":""(.*?)""", match)
link := StrReplace(match1, "\")
Gui, Imgur: New, +hwndhGui
Gui, Imgur: Default
Gui, Font, s9
Gui, Add, Edit, % "w250 h" . (link ? 24 : 120), % link ? link : responsetext
Gui, Font
Gui, Add, Button, x+-80 y+7 w80 h24 gCopyResponse Default, Copy
GuiControl, Focus, Button1
Gui, Show,, Imgur.com
OnMessage( 0x112, Func("WM_SYSCOMMAND").Bind(hGui) )
}
CopyResponse() {
GuiControlGet, Clipboard, Imgur:, Edit1
Gui, Imgur: Destroy
ExitApp
}
WM_SYSCOMMAND(hGui, wp, lp, msg, hwnd) {
static SC_CLOSE := 0xF060
if (wp = SC_CLOSE && hwnd = hGui)
ExitApp
}
CryptBinaryToStringBASE64(pData, Bytes, NOCRLF = "") {
static CRYPT_STRING_BASE64 := 1, CRYPT_STRING_NOCRLF := 0x40000000
CRYPT := CRYPT_STRING_BASE64 | (NOCRLF ? CRYPT_STRING_NOCRLF : 0)
DllCall("Crypt32\CryptBinaryToString", Ptr, pData, UInt, Bytes, UInt, CRYPT, Ptr, 0, UIntP, Chars)
VarSetCapacity(OutData, Chars * (A_IsUnicode ? 2 : 1))
DllCall("Crypt32\CryptBinaryToString", Ptr, pData, UInt, Bytes, UInt, CRYPT, Str, OutData, UIntP, Chars)
Return OutData
}
GetHBitmapFromScreen(x, y, w, h, captureCursor) {
hDC := DllCall("GetDC", Ptr, 0, Ptr)
hBM := DllCall("CreateCompatibleBitmap", Ptr, hDC, Int, w, Int, h, Ptr)
hMDC := DllCall("CreateCompatibleDC", Ptr, hDC, Ptr)
oBM := DllCall("SelectObject", Ptr, hMDC, Ptr, hBM, Ptr)
DllCall("BitBlt", Ptr, hMDC, Int, 0, Int, 0, Int, w, Int, h, Ptr, hDC, Int, x, Int, y, UInt, 0x00CC0020)
( captureCursor && CaptureCursor(hMDC, x, y) )
DllCall("SelectObject", Ptr, hMDC, Ptr, oBM)
DllCall("DeleteDC", Ptr, hMDC)
DllCall("ReleaseDC", Ptr, 0, Ptr, hDC)
Return hBM ; should be deleted with DllCall("DeleteObject", Ptr, hBM)
}
CaptureCursor(hDC, x, y) {
VarSetCapacity(CURSORINFO, szCI := 4*2 + A_PtrSize + 8, 0)
NumPut(szCI, CURSORINFO)
DllCall("GetCursorInfo", Ptr, &CURSORINFO)
bShow := NumGet(CURSORINFO, 4, "UInt")
hCursor := NumGet(CURSORINFO, 4*2)
xCursor := NumGet(CURSORINFO, 4*2 + A_PtrSize, "Int")
yCursor := NumGet(CURSORINFO, 4*2 + A_PtrSize + 4, "Int")
if bShow && hCursor := DllCall("CopyIcon", Ptr, hCursor, Ptr) {
VarSetCapacity(ICONINFO, 4*2 + A_PtrSize*3, 0)
DllCall("GetIconInfo", Ptr, hCursor, Ptr, &ICONINFO)
bIcon := NumGet(ICONINFO, "UInt")
xHotspot := NumGet(ICONINFO, 4, "UInt")
yHotspot := NumGet(ICONINFO, 4*2, "UInt")
hBMMask := NumGet(ICONINFO, 4*2 + A_PtrSize)
hBMColor := NumGet(ICONINFO, 4*2 + A_PtrSize*2)
DllCall("DrawIcon", Ptr, hDC, Int, xCursor - xHotspot - x, Int, yCursor - yHotspot - y, Ptr, hCursor)
DllCall("DestroyIcon", Ptr, hCursor)
( hBMMask && DllCall("DeleteObject", Ptr, hBMMask) )
( hBMColor && DllCall("DeleteObject", Ptr, hBMColor) )
}
}
class GDIplus {
__New() {
if !DllCall("GetModuleHandle", Str, "gdiplus", Ptr)
DllCall("LoadLibrary", Str, "gdiplus")
VarSetCapacity(si, A_PtrSize = 8 ? 24 : 16, 0), si := Chr(1)
DllCall("gdiplus\GdiplusStartup", PtrP, pToken, Ptr, &si, Ptr, 0)
this.token := pToken
}
__Delete() {
DllCall("gdiplus\GdiplusShutdown", Ptr, this.token)
if hModule := DllCall("GetModuleHandle", Str, "gdiplus", Ptr)
DllCall("FreeLibrary", Ptr, hModule)
}
BitmapFromHBitmap(hBitmap, Palette := 0) {
DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", Ptr, hBitmap, Ptr, Palette, PtrP, pBitmap)
return pBitmap ; should be deleted with this.DisposeImage(pBitmap)
}
SaveBitmap(pBitmap, ByRef info, Quality := 75, tobuff := "")
{
; info — если копируем в буфер, тогда расширение файла, если в файл, тогда путь к файлу
if tobuff
Extension := info
else
SplitPath, info,,, Extension
if Extension not in BMP,DIB,RLE,JPG,JPEG,JPE,JFIF,GIF,TIF,TIFF,PNG
return -1
DllCall("gdiplus\GdipGetImageEncodersSize", UintP, nCount, UintP, 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 RegExMatch(Extension, "i)^J(PG|PEG|PE|FIF)$") && Quality != 75 {
DllCall("gdiplus\GdipGetEncoderParameterListSize", Ptr, pBitmap, Ptr, pCodec, UintP, 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_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
}
}
}
if !tobuff
E := DllCall("gdiplus\GdipSaveImageToFile", Ptr, pBitmap, WStr, info, Ptr, pCodec, UInt, p ? p : 0)
else {
DllCall( "ole32\CreateStreamOnHGlobal", UInt, 0, Int, 1, PtrP, pStream )
if !E := DllCall( "gdiplus\GdipSaveImageToStream", Ptr, pBitmap, Ptr, pStream, Ptr, pCodec, UInt, p ? p : 0 ) {
DllCall( "ole32\GetHGlobalFromStream", Ptr, pStream, PtrP, hData )
pData := DllCall( "GlobalLock", Ptr, hData, Ptr )
nSize := DllCall( "GlobalSize", Ptr, hData, Ptr )
VarSetCapacity( info, 0), VarSetCapacity( info, nSize, 0 )
DllCall( "RtlMoveMemory", Ptr, &info, Ptr, pData, UInt, nSize )
DllCall( "GlobalUnlock", Ptr, hData )
DllCall( "GlobalFree", Ptr, hData )
}
ObjRelease(pStream)
}
return E ? -4 : tobuff ? nSize : 0
}
DisposeImage(pBitmap) {
return DllCall("gdiplus\GdipDisposeImage", Ptr, pBitmap)
}
}teadrinker, а что, если добавить проверку наличия в буфере изображения, полученного перед запуском скрипта в другой программе? В случае, например, если перед запуском скрипта выделил участок экрана другим скриптом, или нажал Alt+PrnScr и т.д.?
Это другая задача будет. Здесь мы получаем данные непосредственно с экрана, а если нужно из буфера обмена, есть функция:
Gdip_CreateBitmapFromClipboard()
{
if !DllCall("OpenClipboard", Ptr, 0)
return -1
if !DllCall("IsClipboardFormatAvailable", UInt, 8)
return -2
if !hBitmap := DllCall("GetClipboardData", UInt, 2, Ptr)
return -3
if !pBitmap := Gdip_CreateBitmapFromHBITMAP(hBitmap)
return -4
if !DllCall("CloseClipboard")
return -5
DeleteObject(hBitmap)
return pBitmap
}Полученный таким образом pBitmap нужно будет вставить вместо
...
for k, v in ["x", "y", "w", "h"]
if ( (%v% := oCoords[k]) + 0 = "" && empty := true )
break
if empty {
Sysget, x, 76
Sysget, y, 77
Sysget, w, 78
Sysget, h, 79
}
hBitmap := GetHBitmapFromScreen(x, y, w, h, captureCursor)
gdip := new GDIplus
pBitmap := gdip.BitmapFromHBitmap(hBitmap)
...Думал, хотя бы «спасибо» скажут.
Что-ж, тогда хотя бы я скажу спасибо за эту наработку! На моем компьютере работает все отлично, но я слышал, что у кого виндовс старше XP с gdi проблемы могут возникать? Можете подсказать насколько это точно и если это так то что нужно сделать чтобы избавиться от проблем (я планирую использовать эту функцию на многих компьютерах)?
Не знаю, о каких проблемах идёт речь. Могло иметься в виду отсутствие на компьютере gdiplus.dll, это возможно на системах XP и более ранних, но я не сталкивался, у меня на XP всё было в порядке.
Gdiplus.dll входит в состав Windows XP. Информацию о том, какие операционные системы должны использовать определенный класс или метод, см. Дополнительная информация раздела документация для класса или метода. GDI + доступен в качестве распространяемого для Windows NT 4.0 SP6, Windows 2000, Windows 98 и Windows Me.
скачать последнюю распространяемую
https://docs.microsoft.com/ru-ru/window … -gdi-start
Под "старше" имел ввиду возраст, видимо двусмысленно выразился. Столкнулся с проблемой, что в полноэкранном приложении (игра) следующий код игнорирует приложение и снимает весь экран, как-будто экран приложения прозрачен - это решить возможно?
SaveScreen(filePath) {
hBitmap := GetHBitmapFromScreen(0, 0, A_ScreenWidth, A_ScreenHeight)
gdip := new GDIplus
pBitmap := gdip.BitmapFromHBitmap(hBitmap)
DllCall("DeleteObject", Ptr, hBitmap)
gdip.SaveBitmapToFile(pBitmap, filePath)
gdip.DisposeImage(pBitmap)
}
GetHBitmapFromScreen(x, y, w, h) {
hDC := DllCall("GetDC", Ptr, 0, Ptr)
hBM := DllCall("CreateCompatibleBitmap", Ptr, hDC, Int, w, Int, h, Ptr)
pDC := DllCall("CreateCompatibleDC", Ptr, hDC, Ptr)
oBM := DllCall("SelectObject", Ptr, pDC, Ptr, hBM, Ptr)
DllCall("BitBlt", Ptr, pDC, Int, 0, Int, 0, Int, w, Int, h, Ptr, hDC, Int, x, Int, y, UInt, 0x00CC0020)
DllCall("SelectObject", Ptr, pDC, Ptr, oBM)
DllCall("DeleteDC", Ptr, pDC)
DllCall("ReleaseDC", Ptr, 0, Ptr, hDC)
Return hBM ; should be deleted with DllCall("DeleteObject", Ptr, hBM)
}
class GDIplus {
__New() {
if !DllCall("GetModuleHandle", Str, "gdiplus", Ptr)
DllCall("LoadLibrary", Str, "gdiplus")
VarSetCapacity(si, A_PtrSize = 8 ? 24 : 16, 0), si := Chr(1)
DllCall("gdiplus\GdiplusStartup", PtrP, pToken, Ptr, &si, Ptr, 0)
this.token := pToken
}
__Delete() {
DllCall("gdiplus\GdiplusShutdown", Ptr, this.token)
if hModule := DllCall("GetModuleHandle", Str, "gdiplus", Ptr)
DllCall("FreeLibrary", Ptr, hModule)
}
BitmapFromHBitmap(hBitmap, Palette := 0) {
DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", Ptr, hBitmap, Ptr, Palette, PtrP, pBitmap)
return pBitmap ; should be deleted with this.DisposeImage(pBitmap)
}
SaveBitmapToFile(pBitmap, sOutput, Quality=75) {
SplitPath, sOutput,,, Extension
if Extension not in BMP,DIB,RLE,JPG,JPEG,JPE,JFIF,GIF,TIF,TIFF,PNG
return -1
DllCall("gdiplus\GdipGetImageEncodersSize", UIntP, nCount, UIntP, 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 RegExMatch(Extension, "i)^J(PG|PEG|PE|FIF)$") && Quality != 75 {
DllCall("gdiplus\GdipGetEncoderParameterListSize", Ptr, pBitmap, Ptr, pCodec, UintP, 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_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
}
}
}
if A_IsUnicode
pOutput := &sOutput
else {
VarSetCapacity(wOutput, StrPut(sOutput, "UTF-16")*2, 0)
StrPut(sOutput, &wOutput, "UTF-16")
pOutput := &wOutput
}
E := DllCall("gdiplus\GdipSaveImageToFile", Ptr, pBitmap, Ptr, pOutput, Ptr, pCodec, UInt, p ? p : 0)
return E ? -5 : 0
}
DisposeImage(pBitmap) {
return DllCall("gdiplus\GdipDisposeImage", Ptr, pBitmap)
}
}Можно через directx.
Нужно хукать endscene и запрашивать getbackbuffer.
Я когда этим интересовался - пытался заинжектить через minhook одну тест-игру у меня она тупо вылетала.
На оф.форуме мне не ответили и я нашел человека, который вроде как инжектит dll в игры без проблем.
Он сказал, что попытается помочь мне в этом вопросе, но так ничего и не ответил.
Можете его подоставать. ![]()
https://www.vogons.org/viewtopic.php?f= … 80#p734478
Если разберетесь, как инжектить без вылетов, то тогда лишь останется модернизировать эти скрипты:
http://forum.script-coding.com/viewtopic.php?id=14508
http://forum.script-coding.com/viewtopic.php?id=14540
Похоже мне выгоднее будет через паинт делать скрины
.
Это как — через паинт?
Попробуйте это:
DllCall("BitBlt", Ptr, pDC, Int, 0, Int, 0, Int, w, Int, h, Ptr, hDC, Int, x, Int, y, UInt, 0x00CC0020)заменить на:
DllCall("BitBlt", Ptr, pDC, Int, 0, Int, 0, Int, w, Int, h, Ptr, hDC, Int, x, Int, y, UInt, 0x40000000|0x00CC0020)teadrinker, это делать стандартный скриншот экрана (printscreen), создавать приложение paint и вставлять туда картинку, после чего сохранять. Malcev, сейчас попробую.
UPD: не помогло.
А зачем paint нужен, если изображение есть в буфере обмена? Не понимаю.
teadrinker, тогда сможете мне подсказать как делать скриншот из полноэкранного приложения?
Если после нажатия PrintScreen в буфере обмена есть нужное изображение, его можно сохранить из буфера обмена, смотрите выше.
teadrinker, понял, завтра попробую.
Можно как-то несколько скриншотов сохранить? чтобы они сохранялись как test.png test1.png test2.png и прочее? А то при повторе скрипта файл перезаписывается.
И еще, как по аналогии с...
SaveScreenshotToFile(0, 0, A_ScreenWidth, A_ScreenHeight, A_ScriptDir . "\test.png")
;Run, % A_ScriptDir . "\test.png"
SaveScreenshotToFile(x, y, w, h, filePath) {
hBitmap := GetHBitmapFromScreen(x, y, w, h)
gdip := new GDIplus
pBitmap := gdip.BitmapFromHBitmap(hBitmap)
DllCall("DeleteObject", Ptr, hBitmap)
gdip.SaveBitmapToFile(pBitmap, filePath)
gdip.DisposeImage(pBitmap)
}...записать текст в файл командой FileAppend?
Т.е. чтобы функция создавала, к примеру, файл в директории нахождения скрипта с записью в него содержимого. Типо такого:
SaveTxt(A_ScriptDir . "\test.txt")
SaveTxt(filePath) {
FileAppend(Записать переменную %a% и %b% в файл.`n, filePath)
}Вобще непонятно как использовать в данном случае команду A_ScriptDir для "\test.txt"
Можно как-то несколько скриншотов сохранить?
SaveScreenshotToFile(0, 0, A_ScreenWidth, A_ScreenHeight, A_ScriptDir . "\test1.png")
SaveScreenshotToFile(0, 0, A_ScreenWidth, A_ScreenHeight, A_ScriptDir . "\test2.png")
;Run, % A_ScriptDir . "\test.png"
SaveScreenshotToFile(x, y, w, h, filePath) {
hBitmap := GetHBitmapFromScreen(x, y, w, h)
gdip := new GDIplus
pBitmap := gdip.BitmapFromHBitmap(hBitmap)
DllCall("DeleteObject", Ptr, hBitmap)
gdip.SaveBitmapToFile(pBitmap, filePath)
gdip.DisposeImage(pBitmap)
}записать текст в файл командой FileAppend?
Если вопрос не связан с темой топика, создайте новый, и сформулируйте вопрос более точно.
SaveScreenshotToFile(0, 0, A_ScreenWidth, A_ScreenHeight, A_ScriptDir . "\test1.png") SaveScreenshotToFile(0, 0, A_ScreenWidth, A_ScreenHeight, A_ScriptDir . "\test2.png")
Нет, я имею ввиду чтобы они создавались по счетчику не повторяя имена предыдущих. А не все сразу.
Как-то использовать count в назначении имени, чтобы при последующем нажатии ключа создавался еще один скриншот там же, но с именем, отличным от первого. Так они перезаписываются.
сформулируйте вопрос более точно.
Я имел ввиду что вместо PrintScreen будет команда FileAppend, но уже вроде понял что надо подставить A_ScriptDir в условие.
Но тут тоже не мешало бы использовать счетчик, чтобы записи нумеровались в файле, а не шли просто одна за другой.
Счётчик можно так организовать:
i := 0
F10:: SaveScreenshotToFile(0, 0, A_ScreenWidth, A_ScreenHeight, A_ScriptDir . "\test" . ++i . ".png")Счётчик можно так организовать:
i := 0 F10:: SaveScreenshotToFile(0, 0, A_ScreenWidth, A_ScreenHeight, A_ScriptDir . "\test" . ++i . ".png")
Нет, доходит до test1 и им начинает заменять все предыдущие.
Где-то нужен сброс счетчика, и уникальное имя.
Или проверку: Если файл test ++i уже существует, то +++i что-то такое
Или
DllCall("DeleteObject", Ptr, hBitmap)помоему там в коде, что-то отвечает за удаление чего-то, но я точно не понял
Нет, не начинает. Наверно как-то криво написали. Покажите свой код полностью.
Нет, не начинает. Наверно как-то криво написали. Покажите свой код полностью.
4::
ToolTip, Скриншот сохранён.
sleep 200
ToolTip
{
i := 0
SaveScreenshotToFile(0, 0, A_ScreenWidth, A_ScreenHeight, A_ScriptDir . "\test" . ++i . ".png")
;Run, % A_ScriptDir . "\test.png"
SaveScreenshotToFile(x, y, w, h, filePath) {
hBitmap := GetHBitmapFromScreen(x, y, w, h)
gdip := new GDIplus
pBitmap := gdip.BitmapFromHBitmap(hBitmap)
DllCall("DeleteObject", Ptr, hBitmap)
gdip.SaveBitmapToFile(pBitmap, filePath)
gdip.DisposeImage(pBitmap)
}
GetHBitmapFromScreen(x, y, w, h) {
hDC := DllCall("GetDC", Ptr, 0, Ptr)
hBM := DllCall("CreateCompatibleBitmap", Ptr, hDC, Int, w, Int, h, Ptr)
pDC := DllCall("CreateCompatibleDC", Ptr, hDC, Ptr)
oBM := DllCall("SelectObject", Ptr, pDC, Ptr, hBM, Ptr)
DllCall("BitBlt", Ptr, pDC, Int, 0, Int, 0, Int, w, Int, h, Ptr, hDC, Int, x, Int, y, UInt, 0x00CC0020)
DllCall("SelectObject", Ptr, pDC, Ptr, oBM)
DllCall("DeleteDC", Ptr, pDC)
DllCall("ReleaseDC", Ptr, 0, Ptr, hDC)
Return hBM ; should be deleted with DllCall("DeleteObject", Ptr, hBM)
}
class GDIplus {
__New() {
if !DllCall("GetModuleHandle", Str, "gdiplus", Ptr)
DllCall("LoadLibrary", Str, "gdiplus")
VarSetCapacity(si, A_PtrSize = 8 ? 24 : 16, 0), si := Chr(1)
DllCall("gdiplus\GdiplusStartup", PtrP, pToken, Ptr, &si, Ptr, 0)
this.token := pToken
}
__Delete() {
DllCall("gdiplus\GdiplusShutdown", Ptr, this.token)
if hModule := DllCall("GetModuleHandle", Str, "gdiplus", Ptr)
DllCall("FreeLibrary", Ptr, hModule)
}
BitmapFromHBitmap(hBitmap, Palette := 0) {
DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", Ptr, hBitmap, Ptr, Palette, PtrP, pBitmap)
return pBitmap ; should be deleted with this.DisposeImage(pBitmap)
}
SaveBitmapToFile(pBitmap, sOutput, Quality=75) {
SplitPath, sOutput,,, Extension
if Extension not in BMP,DIB,RLE,JPG,JPEG,JPE,JFIF,GIF,TIF,TIFF,PNG
return -1
DllCall("gdiplus\GdipGetImageEncodersSize", UIntP, nCount, UIntP, 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 RegExMatch(Extension, "i)^J(PG|PEG|PE|FIF)$") && Quality != 75 {
DllCall("gdiplus\GdipGetEncoderParameterListSize", Ptr, pBitmap, Ptr, pCodec, UintP, 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_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
}
}
}
if A_IsUnicode
pOutput := &sOutput
else {
VarSetCapacity(wOutput, StrPut(sOutput, "UTF-16")*2, 0)
StrPut(sOutput, &wOutput, "UTF-16")
pOutput := &wOutput
}
E := DllCall("gdiplus\GdipSaveImageToFile", Ptr, pBitmap, Ptr, pOutput, Ptr, pCodec, UInt, p ? p : 0)
return E ? -5 : 0
}
DisposeImage(pBitmap) {
return DllCall("gdiplus\GdipDisposeImage", Ptr, pBitmap)
}
}
return
}fgslm
Логика просто на высшем уровне:
4::
ToolTip, Скриншот сохранён.
sleep 200
ToolTip
...Сначала отобразить информации о сохранении, подождать (окно изменит что-нибудь) и сохранить. Это же не верно.
Не легче в имени файла добавлять время? Я так скриншотам имя выдаю:
FileName := T A_YYYY "." A_MM "." A_DD " (" A_Hour "." A_Min "." A_Sec "." A_MSec ")." FormatЭто же не верно
А почему это неработает с точки зрения логики языка? Там же нет никаких команд - просто вывод информации.
Где там скобки надо поставить чтобы последовательно выполнялось?
fgslm
Логика просто на высшем уровне:
4:: ToolTip, Скриншот сохранён. sleep 200 ToolTip ...Сначала отобразить информации о сохранении, подождать (окно изменить что-нибудь) и сохранить. Это же не верно.
Не легче в имени файла добавлять время? Я так скриншотам имя выдаю:
FileName := T A_YYYY "." A_MM "." A_DD " (" A_Hour "." A_Min "." A_Sec "." A_MSec ")." Format
Я чет неверное не туда поставил, но у меня не работает
4::
;ToolTip, Скриншот сохранён.
;sleep 20
;ToolTip
FileName := T A_YYYY "." A_MM "." A_DD " (" A_Hour "." A_Min "." A_Sec "." A_MSec ")." Format
;i := 0
;SaveScreenshotToFile(0, 0, A_ScreenWidth, A_ScreenHeight, A_ScriptDir . "\FileName" . ++i . ".png")
SaveScreenshotToFile(0, 0, A_ScreenWidth, A_ScreenHeight, A_ScriptDir . "\FileName" . . ".png")
;Run, % A_ScriptDir . "\test.png"
SaveScreenshotToFile(x, y, w, h, filePath) {
hBitmap := GetHBitmapFromScreen(x, y, w, h)
gdip := new GDIplus
pBitmap := gdip.BitmapFromHBitmap(hBitmap)
DllCall("DeleteObject", Ptr, hBitmap)
gdip.SaveBitmapToFile(pBitmap, filePath)
gdip.DisposeImage(pBitmap)
}один файл создал и всё.
fgslm
Не нужно глупо копировать чужой код. Я предоставил лишь одну строку, у вас же нет переменных 'T' и 'Format' как у меня.
Примерно так будет выглядеть код:
4::
Format := "jpg"
Quality := 55
T := % A_ScriptDir "\ScreenS1\"
FileName := T . A_YYYY "." A_MM "." A_DD " (" A_Hour "." A_Min "." A_Sec "." A_MSec ")." Format
FileCreateDir, % T
SaveScreenshotToFile(FileName)
Return
SaveScreenshotToFile(filePath, x := 0, y := 0, w := 0, h := 0, Quality := 75)
{
If (W+H < 2)
{
W := A_ScreenWidth
H := A_ScreenHeight
}
hBitmap := GetHBitmapFromScreen(x, y, w, h)
gdip := new GDIplus
pBitmap := gdip.BitmapFromHBitmap(hBitmap)
DllCall("DeleteObject", Ptr, hBitmap)
gdip.SaveBitmapToFile(pBitmap, filePath, Quality)
gdip.DisposeImage(pBitmap)
}Примерно так будет выглядеть код:
Понятно. У меня всё равно не работает. Там половины переменных в виде функций нет.
Но мне сама идея первого поста понравилась - то, что по нажатию можно сохранять скриншот без сторонних программ. Но вот отсуствие потока смены имён, и как следствие нескольких скриншотов подряд ... это минус.
Я надеялся как-то так сделать
Или проверку: Если файл test ++i уже существует, то +++i что-то такое
Со временем конечно не новая идея, но не всё же к нему привязываться.
Вот весь код, должно заработать я полагаю (если есть GDIplus):
4::
Format := "jpg"
Quality := 55
T := % A_ScriptDir "\ScreenS1\"
FileName := T . A_YYYY "." A_MM "." A_DD " (" A_Hour "." A_Min "." A_Sec "." A_MSec ")." Format
FileCreateDir, % T
SaveScreenshotToFile(FileName)
Return
SaveScreenshotToFile(filePath, x := 0, y := 0, w := 0, h := 0, Quality := 75)
{
If (W+H < 2)
{
W := A_ScreenWidth
H := A_ScreenHeight
}
hBitmap := GetHBitmapFromScreen(x, y, w, h)
gdip := new GDIplus
pBitmap := gdip.BitmapFromHBitmap(hBitmap)
DllCall("DeleteObject", Ptr, hBitmap)
gdip.SaveBitmapToFile(pBitmap, filePath, Quality)
gdip.DisposeImage(pBitmap)
}
GetHBitmapFromScreen(x, y, w, h) {
hDC := DllCall("GetDC", Ptr, 0, Ptr)
hBM := DllCall("CreateCompatibleBitmap", Ptr, hDC, Int, w, Int, h, Ptr)
pDC := DllCall("CreateCompatibleDC", Ptr, hDC, Ptr)
oBM := DllCall("SelectObject", Ptr, pDC, Ptr, hBM, Ptr)
DllCall("BitBlt", Ptr, pDC, Int, 0, Int, 0, Int, w, Int, h, Ptr, hDC, Int, x, Int, y, UInt, 0x00CC0020)
DllCall("SelectObject", Ptr, pDC, Ptr, oBM)
DllCall("DeleteDC", Ptr, pDC)
DllCall("ReleaseDC", Ptr, 0, Ptr, hDC)
Return hBM ; should be deleted with DllCall("DeleteObject", Ptr, hBM)
}
class GDIplus {
__New() {
if !DllCall("GetModuleHandle", Str, "gdiplus", Ptr)
DllCall("LoadLibrary", Str, "gdiplus")
VarSetCapacity(si, A_PtrSize = 8 ? 24 : 16, 0), si := Chr(1)
DllCall("gdiplus\GdiplusStartup", PtrP, pToken, Ptr, &si, Ptr, 0)
this.token := pToken
}
__Delete() {
DllCall("gdiplus\GdiplusShutdown", Ptr, this.token)
if hModule := DllCall("GetModuleHandle", Str, "gdiplus", Ptr)
DllCall("FreeLibrary", Ptr, hModule)
}
BitmapFromHBitmap(hBitmap, Palette := 0) {
DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", Ptr, hBitmap, Ptr, Palette, PtrP, pBitmap)
Return pBitmap ; should be deleted with this.DisposeImage(pBitmap)
}
SaveBitmapToFile(pBitmap, sOutput, Quality=75) {
SplitPath, sOutput,,, Extension
if Extension not in BMP,DIB,RLE,JPG,JPEG,JPE,JFIF,GIF,TIF,TIFF,PNG
Return -1
DllCall("gdiplus\GdipGetImageEncodersSize", UIntP, nCount, UIntP, 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 RegExMatch(Extension, "i)^J(PG|PEG|PE|FIF)$") && Quality != 75 {
DllCall("gdiplus\GdipGetEncoderParameterListSize", Ptr, pBitmap, Ptr, pCodec, UintP, 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_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
}
}
}
if A_IsUnicode
pOutput := &sOutput
else {
VarSetCapacity(wOutput, StrPut(sOutput, "UTF-16")*2, 0)
StrPut(sOutput, &wOutput, "UTF-16")
pOutput := &wOutput
}
E := DllCall("gdiplus\GdipSaveImageToFile", Ptr, pBitmap, Ptr, pOutput, Ptr, pCodec, UInt, p ? p : 0)
Return E ? -5 : 0
}
DisposeImage(pBitmap) {
Return DllCall("gdiplus\GdipDisposeImage", Ptr, pBitmap)
}
}
ReturnВот весь код, должно заработать я полагаю (если есть GDIplus):
4:: Format := "jpg" Quality := 55 T := % A_ScriptDir "\ScreenS1\" FileName := T . A_YYYY "." A_MM "." A_DD " (" A_Hour "." A_Min "." A_Sec "." A_MSec ")." Format FileCreateDir, % T SaveScreenshotToFile(FileName) Return SaveScreenshotToFile(filePath, x := 0, y := 0, w := 0, h := 0, Quality := 75) { If (W+H < 2) { W := A_ScreenWidth H := A_ScreenHeight } hBitmap := GetHBitmapFromScreen(x, y, w, h) gdip := new GDIplus pBitmap := gdip.BitmapFromHBitmap(hBitmap) DllCall("DeleteObject", Ptr, hBitmap) gdip.SaveBitmapToFile(pBitmap, filePath, Quality) gdip.DisposeImage(pBitmap) } GetHBitmapFromScreen(x, y, w, h) { hDC := DllCall("GetDC", Ptr, 0, Ptr) hBM := DllCall("CreateCompatibleBitmap", Ptr, hDC, Int, w, Int, h, Ptr) pDC := DllCall("CreateCompatibleDC", Ptr, hDC, Ptr) oBM := DllCall("SelectObject", Ptr, pDC, Ptr, hBM, Ptr) DllCall("BitBlt", Ptr, pDC, Int, 0, Int, 0, Int, w, Int, h, Ptr, hDC, Int, x, Int, y, UInt, 0x00CC0020) DllCall("SelectObject", Ptr, pDC, Ptr, oBM) DllCall("DeleteDC", Ptr, pDC) DllCall("ReleaseDC", Ptr, 0, Ptr, hDC) Return hBM ; should be deleted with DllCall("DeleteObject", Ptr, hBM) } class GDIplus { __New() { if !DllCall("GetModuleHandle", Str, "gdiplus", Ptr) DllCall("LoadLibrary", Str, "gdiplus") VarSetCapacity(si, A_PtrSize = 8 ? 24 : 16, 0), si := Chr(1) DllCall("gdiplus\GdiplusStartup", PtrP, pToken, Ptr, &si, Ptr, 0) this.token := pToken } __Delete() { DllCall("gdiplus\GdiplusShutdown", Ptr, this.token) if hModule := DllCall("GetModuleHandle", Str, "gdiplus", Ptr) DllCall("FreeLibrary", Ptr, hModule) } BitmapFromHBitmap(hBitmap, Palette := 0) { DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", Ptr, hBitmap, Ptr, Palette, PtrP, pBitmap) Return pBitmap ; should be deleted with this.DisposeImage(pBitmap) } SaveBitmapToFile(pBitmap, sOutput, Quality=75) { SplitPath, sOutput,,, Extension if Extension not in BMP,DIB,RLE,JPG,JPEG,JPE,JFIF,GIF,TIF,TIFF,PNG Return -1 DllCall("gdiplus\GdipGetImageEncodersSize", UIntP, nCount, UIntP, 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 RegExMatch(Extension, "i)^J(PG|PEG|PE|FIF)$") && Quality != 75 { DllCall("gdiplus\GdipGetEncoderParameterListSize", Ptr, pBitmap, Ptr, pCodec, UintP, 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_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 } } } if A_IsUnicode pOutput := &sOutput else { VarSetCapacity(wOutput, StrPut(sOutput, "UTF-16")*2, 0) StrPut(sOutput, &wOutput, "UTF-16") pOutput := &wOutput } E := DllCall("gdiplus\GdipSaveImageToFile", Ptr, pBitmap, Ptr, pOutput, Ptr, pCodec, UInt, p ? p : 0) Return E ? -5 : 0 } DisposeImage(pBitmap) { Return DllCall("gdiplus\GdipDisposeImage", Ptr, pBitmap) } } Return
УУУ Круть!
Он еще и папочку создаёт)
Всёравно я прикрутил
ToolTip Скриншот создан
sleep 2000
ToolTipИ жду секунду прежде чем он сохранится. Оповещения не хватает.
По этой же аналогии хотелось бы увидеть применение команды FileAppend со счётчиком,
Например
первый клик, вид строки: Строка 1, переменная1, переменная2, переменная3
второй клик: Строка2, переменная1, переменная2, переменная3, переменная4
третий клик: Строка3, переменная6, переменная8, переменная2, переменная9по типу: Если создана запись в файл, то ей присваивается номер(№1 начиная со старта скрипта, или обнуление по ключу, но тут FileDelete сгодится) создаётся оповещение об этом(подтверждает успешность выполнения), и предлагает создать следующую, но уже присваивает ей №2 в файле и так далее, до бесконечности.
+ Функция удаления предыдущей записи по ключу
т.к. я пока сейчас пользуюсь:
A::
{
ToolTip, Предыдущая запись неверна `nЗадайте новую
FileAppend, Предыдущая строка неверна`nНовая строка:`n, %A_ScriptDir%\Test.txt
SoundPlay, %A_ScriptDir%\New.wav
return
}Страницы 1
Чтобы отправить ответ, вы должны войти или зарегистрироваться