Тема: 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
Чтобы отправить ответ, вы должны войти или зарегистрироваться