51

Re: AHK: графика

Там конечно довольно изящное решение применено, но чтобы сделать скриншот таким скриншоттером нужно больше времени чем моим, причём как раз из-за гуи: его надо вручную двигать и ресайзить.
К тому же, насколько я понял из кода - там используется создание обычного GUI окна с помощью AHK, у которого убираются все тулбары и рамки так, что видимым остаётся только контент окна, и всё содержимое этого окна просто заливается с помощью GDI+ обычным прямоугольником:

DllCall("gdiplus\GdipFillRectangle", UInt, G, Int, pBrush, "float", 0, "float", 0, "float", w, "float", h)

Мне же - не нужно создандие GUI окна, мне нужно рисовать поверх всего экрана (и мне нужно Gdip_DrawLines(), т.к. хочу только рамку от прямоугольника, а не сам прямоугольник).

52

Re: AHK: графика

А может я не правильно понял, как работает GDI+: судя по примерам - там везде всё равно создаётся GUI окно сначала.
В любом случае, я настолько не силён в этом, что даже готовый скрипт от teadrinker'а не смогу переделать под свои нужды sad

53 (изменено: Drugoy, 2013-02-26 21:47:21)

Re: AHK: графика

см. след. сообщение

54

Re: AHK: графика

Если хорошо поискать, на форуме есть тема "Сохранить произвольный кусок экрана".

55

Re: AHK: графика

Drugoy пишет:

а дальше загрузка ядра процессора под 100% и скрипт ни на что не реагирует:

Добавьте в цикл небольшой Sleep, хотя бы на 100 мс.

56

Re: AHK: графика

Всем спасибо, вопрос решён:

~Esc::
Clean:
    Gui 1: Destroy
    firstTimeHit :=
Return

...

~PrintScreen:: ; Since we use the same hotkey twice, we have to distinguish the calls
KeyWait, PrintScreen
If !(firstTimeHit = true)
{
    firstTimeHit := true
    pToken := Gdip_Startup()
    MouseGetPos, x1, y1
    Gui, 1: -Caption +E0x80000 +HWNDhwnd1 +LastFound +AlwaysOnTop +ToolWindow +OwnDialogs
    Gui, 1: Show, NA
    Loop
    {
        If GetKeyState("PrintScreen","P") || GetKeyState("Escape", "P") || GetKeyState("LButton", "P")
        {
            KeyWait, PrintScreen
            Break
        }
        Sleep 20
        MouseGetPos, x2, y2
        If !(x1 = x2 || y1 = y2)
        {
            Gosub, x1x2
            hbm := CreateDIBSection(A_ScreenWidth, A_ScreenHeight)
            hdc := CreateCompatibleDC()
            obm := SelectObject(hdc, hbm)
            G := Gdip_GraphicsFromHDC(hdc)
            Gdip_SetSmoothingMode(G, 4)
            pPen := Gdip_CreatePen(0xffff0000, 1)
            Gdip_DrawLines(G, pPen, x1 "," y1 "|" x2 "," y1 "|" x2 "," y2 "|" x1 "," y2 "|" x1 "," y1)
            Gdip_DeleteBrush(pPen)
            UpdateLayeredWindow(hwnd1, hdc, 0, 0, A_ScreenWidth, A_ScreenHeight)
            SelectObject(hdc, obm)
            DeleteObject(hbm)
            DeleteDC(hdc)
            Gdip_DeleteGraphics(G)
        }
    }
    Return
}
Else

...

x1x2:
    If x1 > x2    ; We have to keep x1 < x2 and y1 < y2 or GDI+ function will fail.
    {
        x3 := x2
        x2 := x1
        x1 := x3
    }
    If y1 > y2    ; We have to keep y1 < y2 and y1 < y2 or GDI+ function will fail.
    {
        y3 := y2
        y2 := y1
        y1 := y3
    }
Return

57

Re: AHK: графика

Раз уж тут обсуждается графика, решил не создавать новую тему и задать свою кучу вопросов тут. Авось, кто знает, в какую сторону мне танцевать...
Все вышеописанное в этом разделе я довольно активно использую в своих скриптах, но недавно уперся, как головой в стену в одно ограничение GDI+.
Все способы рисования (по крайней мере из того массива, который поддерживает gdip.ahk) основаны на методах объекта Graphics. Прямоугольник рисуется методом DrawRectangle, линия - методом DrawLine и т.д.
Но методы - не есть объекты. Нарисовал ты линию, она отобразилась на растровом изображении, и единственный, кто помнит, что была нарисована линия - сам рисунок с измененными в нужных местах пикселами. Все, больше с этой линией ничего сделать нельзя, только стереть чем-нибудь позже нарисованным, вернув пиксели к исходному цвету, ну и заменить цвет линии, да и то, если не применено сглаживание.
А мне же нужна та же линия, как управляемый объект, что реализовано в большинстве векторных редакторов.
То есть, чтобы по ходу действия можно было менять ее цвет, толщину, положение, не затрагивая при этом другие объекты.
Попытавшись курить документацию по GDI+, я обнаружил, что все-таки можно создавать объекты Point и Rectangle, у которых есть свои свойства и методы и даже (ура!) есть "Например, методы Inflate и Offset позволяют изменять размер и расположение прямоугольника. Метод IntersectsWith позволяет определить, не пересекается ли данный прямоугольник с некоторым указанным прямоугольником, а метод Contains позволяет определить, находится ли указанная точка внутри данного прямоугольника."
Но, увы, этим все и ограничилось, большего функционала GDI+ не предложила. Да и эти вкусности не поддерживаются в gdip.ahk (ну это, вроде, разрешимо, можно их туда прописать через DllCall, благо, на форуме есть знающие люди, которые подскажут правильный код, но дальше то что?)
Ведь это не даст в итоге нужного функционала.
Но когда я обновился до AHK_L, то узнал, что в нем, оказывается уже есть поддержка объектов просто и даже объектов COM. И тут получается распутье. В какую сторону дальше завернуть?
Разобраться в создании собственных объектов и прикрутить это дело в gdip.ahk?
Как-то по новому подключаться к GDI+ через COM объекты, что позволит реализовать требуемый функционал?
Рисовать многомногослойные рисунки, на каждый объект по слою (имхо, извращение)?
Или плюнуть на все, и коряво реализовать все через стирание и перерисовку объектов, запоминая все их параметры в едреной куче переменных (еще большее извращение)?
Кто что подскажет?

58

Re: AHK: графика

Во-первых, вряд ли возможно рисовать многослойные изображения. Я как ни пытался, одно накладывается на другое, прозрачный фон невозможен.

Во-вторых, по моему представлению, в любом случае нужно перерисовывать картинку, если фигура изменила размер или изменила координаты.
Для создания векторной графической анимации мне приходилось перерисовывать все фигуры поочерёдно (начиная с нижнего, завершая верхним). Размеры все фигур брались из переменных.

59

Re: AHK: графика

ypppu пишет:

Во-первых, вряд ли возможно рисовать многослойные изображения. Я как ни пытался, одно накладывается на другое, прозрачный фон невозможен.

Вот рабочий пример двухслойного изображения, в котором верхний слой прозрачный:


#SingleInstance, Force
#NoEnv
#NoTrayIcon
SetBatchLines, -1
   SetWinDelay, 0
;#Include, Gdip.ahk

If !pToken := Gdip_Startup()
   {
      MsgBox, 48, Ошибка GDI+, Убедитесь в наличии gdiplus.dll в вашей системе!
      ExitApp
   }
   Width := 400
   Height := 200   ; размеры картинки
   DllCall("Winmm\timeBeginPeriod", UInt, 3)
   SleepDuration := 4

Gui, Add, Pic, x10 y10 w%Width% h%Height% hwndhPic  gRepaint 
Gui, Add, Pic, x10 y10 w%Width% h%Height% hwndhPic2  BackgroundTrans
GUI,show,,DualLayer
 gosub StartDraw
WinGet,MyWindow,ID,DualLayer
ControlGetPos,Xpic, Ypic,,,Static1,ahk_id %MyWindow%
OnMessage(0xF, "WM_PAINT")  ; поддержка изображения при перерисовке окна
Settimer, SetTime, 1000
return

StartDraw:
   hbm := CreateDIBSection(Width, Height)
   hdc := CreateCompatibleDC()
   obm := SelectObject(hdc, hbm)
   G := Gdip_GraphicsFromHDC(hdc)
   Gdip_SetSmoothingMode(G, 2)              ;задаем режим сглаживания
   pBlackPen := Gdip_CreatePen(0xff000000, 1)    
   pBluePen := Gdip_CreatePen(0xff0000ff, 1)     ; карандаш для графика
   pWhiteBrush := Gdip_BrushCreateSolid(0xffffffff)   ; кисть для заливки
   Gdip_FillRoundedRectangle(G, pWhiteBrush, 0, 0, Width, Height, 2) ;рисуем белый фон
hPicDC := GetDC(hPic)  ; получаем контекст контрола, чтобы переносить в него изображение
BitBlt(hPicDC, 0, 0, Width, Height, hdc, 0, 0)  ; переносим рисунок в контекст контрола

hbm2 := CreateDIBSection(Width, Height)
hdc2 := CreateCompatibleDC()
obm2 := SelectObject(hdc2, hbm2)
G2 := Gdip_GraphicsFromHDC(hdc2)
Gdip_SetSmoothingMode(G2, 4)
Gdip_FillRectangle(G2, pWhiteBrush, -1, -1, Width, Height)
hPicDC2 := GetDC(hPic2)
BitBlt(hPicDC2, 0, 0, Width, Height, hdc2, 0, 0, 0x008800C6 )   ; SRCAND = 0x008800C6
return

GuiClose:
ReleaseDC(hPicDC2, hPic2), SelectObject(hdc2, obm2), DeleteObject(hbm2)
DeleteDC(hdc2), Gdip_DeleteGraphics(G2)

Gdip_DeleteBrush(pWhiteBrush)
Gdip_DeletePen(pBlackPen)
Gdip_DeletePen(pBluePen)
   ReleaseDC(hPicDC, hPic)
   SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc)
   Gdip_DeleteGraphics(G)
   Gdip_Shutdown(pToken)
   DllCall("Winmm\timeEndPeriod", UInt, 3)
ExitApp

SetTime:
FormatTime, TimeString,, HH:mm:ss
Gdip_FillRectangle(G2, pWhiteBrush, 2, 2, 350, 100)
DrawText(G2, TimeString, "Arial", 0xff000000, 50, 2, 2, 350, 100)
   BitBlt(hPicDC, 0, 0, Width, Height, hdc, 0, 0)
   BitBlt(hPicDC2, 0, 0, Width, Height, hdc2, 0, 0, 0x008800C6 ) ; SRCAND = 0x008800C6
return

Repaint:
   if A_GuiControlEvent = Normal
{
CoordMode,Mouse,Window
MouseGetPos,mX, mY
Ydm := mY - Ypic
Xdm := mX - Xpic
 Settimer, Drawing, 100
KeyWait,LButton
MouseGetPos,mX, mY
Yum := mY - Ypic
Xum := mX - Xpic
 Settimer, Drawing, off
}
Return

Drawing:
CoordMode,Mouse,Window
MouseGetPos,msX, msY
Ydraw := msY - Ypic
Xdraw := msX - Xpic
   MyLine := Gdip_DrawLine(G, pBluePen, Xdm, Ydm, Xdraw, Ydraw)  ;рисуем 
Xdm := Xdraw
Ydm := Ydraw
 BitBlt(hPicDC2, 0, 0, Width, Height, hdc2, 0, 0, 0x008800C6 )   ; SRCAND = 0x008800C6
return

WM_PAINT()   ; поддержка изображения при перерисовке окна
{
   global
   SetTimer, Timer, -10
   Return

Timer:
   BitBlt(hPicDC, 0, 0, Width, Height, hdc, 0, 0)
   BitBlt(hPicDC2, 0, 0, Width, Height, hdc2, 0, 0, 0x008800C6 )   ; SRCAND = 0x008800C6
   Return
}

DrawText(workG, MyText, Font, TextColor=0xff000000, SizeFont=10, Xt=0, Yt=0, Wt=100, Ht=50, Underline=0, Italic=0, Strike=0, Bold=0, Outlined=0)
{
global 
if !Font
Font = Arial
If !hFamily := Gdip_FontFamilyCreate(Font)
{
   MsgBox, 48, Font error!, The font you have specified does not exist on the system
   ExitApp
}
Gdip_DeleteFontFamily(hFamily)
Options := "x" . Xt . " y" . Yt . " w" . Wt . " h" . Ht . " cFF00ff00 r4 center s" . SizeFont . ""
if Underline = 1
Options := Options . " Underline"
if Italic = 1
Options := Options . " Italic"
if Strike = 1
Options := Options . " Strikeout"
if Bold = 1
Options := Options . " Bold"
if !pPath := Gdip_CreatePath(0)
Return errorlevel
Gdip_AddString(pPath, MyText, Font, Options)    
if !pTextBrush := Gdip_BrushCreateSolid(TextColor)
Return errorlevel
Gdip_FillPath(workG, pTextBrush, pPath)
Gdip_DeleteBrush(pTextBrush)
Gdip_DeletePath(pPath)
}


Gdip_AddString(Path, sString,fontName, options,stringFormat=0x4000)
{
   nSize := DllCall("MultiByteToWideChar", "UInt", 0, "UInt", 0, "UInt", &sString, "Int", -1, "UInt", 0, "Int", 0)
   VarSetCapacity(wString, nSize*2)
   DllCall("MultiByteToWideChar", "UInt", 0, "UInt", 0, "UInt", &sString, "Int", -1, "UInt", &wString, "Int", nSize)

    hFamily := Gdip_FontFamilyCreate(fontName)
    RegExMatch(Options, "i)X([\-0-9]+)", xpos)
    RegExMatch(Options, "i)Y([\-0-9]+)", ypos)
    RegExMatch(Options, "i)W([0-9]+)", Width)
    RegExMatch(Options, "i)H([0-9]+)", Height)
    RegExMatch(Options, "i)R([0-9])", Rendering)    
        
    Style := 0, Styles := "Regular|Bold|Italic|BoldItalic|Underline|Strikeout"
    Loop, Parse, Styles, |
    {
        If RegExMatch(Options, "i)\b" A_loopField)
        Style |= (A_LoopField != "StrikeOut") ? (A_Index-1) : 8
    }
    RegExMatch(Options, "i)S([0-9]+)", fontSize)
    Align := 0, Alignments := "Near|Left|Centre|Center|Far|Right"
    Loop, Parse, Alignments, |
    {
        If RegExMatch(Options, "i)\b" A_loopField)
        Align |= A_Index//2.1      ; 0|0|1|1|2|2
    }
    hFormat := Gdip_StringFormatCreate(stringFormat)
    Gdip_SetStringFormatAlign(hFormat, Align)    
    Gdip_SetTextRenderingHint(pGraphics, Rendering)
    CreateRectF(textbox, xpos1, ypos1, Width1, Height1)    
    iRet := DllCall("gdiplus\GdipAddPathString", "UInt", Path,  "UInt", &wString, "Int", -1, "Uint",hFamily, "Int", Style, "Float", fontSize1,"UInt", &textbox, "UInt", hFormat)
    Gdip_DeleteFontFamily(hFamily)
    Gdip_DeleteStringFormat(hFormat)
    return iRet             
}

Gdip_DrawPath(pGraphics, pPen, Path)
{
    return DllCall("gdiplus\GdipDrawPath", "UInt", pGraphics, "UInt", pPen, "UInt", Path)
}

Каждую секунду на верхнем слое перерисовывается отображаемое время, т.е. сначала белым прямоугольником стирается старое, потом пишется новое.
При этом с помощью мыши можно рисовать ломаные линии на нижнем слое. Если их нарисовать "под" текстом, то они все равно будут видны, несмотря на ежесекундно рисуемый поверх них белый прямоугольник.

ypppu пишет:

Во-вторых, по моему представлению, в любом случае нужно перерисовывать картинку, если фигура изменила размер или изменила координаты.
Для создания векторной графической анимации мне приходилось перерисовывать все фигуры поочерёдно (начиная с нижнего, завершая верхним). Размеры все фигур брались из переменных.

Дык, никто не спорит, что там все надо перерисовывать, вопрос в том, как удобнее для кодера организовать хранение этих данных и управление объектами. Мне кажется, что если АНК теперь позволяет работать с объектами, то можно все реализовать через объектную модель. Или написанную собственноручно, или взятую оттуда, где она уже реализована. Как эти данные были организованы у вас?

60

Re: AHK: графика

Мне же - не нужно создандие GUI окна, мне нужно рисовать поверх всего экрана

  И мне нужно рисовать и писать текст без GUI. Это вообще возможно?

61

Re: AHK: графика

Pogodin, нужны подробности. Что значит "рисовать и писать текст без GUI"?

62

Re: AHK: графика

Не создавая нового окна писать и рисовать в уже существующем чужом.

63

Re: AHK: графика

В таком случае не смогу помочь.

Настоящие герои не ищут лёгкий путей:
AHK: Добавить кнопку в произвольное окно (не ahk GUI) ▬►создавать свои окна и контолы в чужом процессе

64

Re: AHK: графика

Pogodin пишет:

Не создавая нового окна писать и рисовать в уже существующем чужом

Рисовать-то можно, вопрос зачем?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

65

Re: AHK: графика

Чтобы вносить нужные элементы без дополнительных окон.

66

Re: AHK: графика

Можно вносить все элементы в одно окно.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

67

Re: AHK: графика

Это хорошо, но нужно без создания собственного под эти элементы.

68

Re: AHK: графика

Ну вот пример рисования в окне cmd:

Run, cmd,,, PID
WinWait, ahk_pid %PID%
Loop 4 {
   WinSet, Redraw
   Sleep, 400
   DrawTextInAnyWindow(WinExist(), "AutoHotkey is cool!", "Verdana", "italic", 40, 0xFF0000, 40, 40)
   Sleep, 400
}

DrawTextInAnyWindow(hwnd, text, FontName, FontStyle, FontSize, FontColorBGR, x, y)
{
   static TRANSPARENT := 1, LOGPIXELSY := 90, ANTIALIASED_QUALITY := 4, mult := A_IsUnicode ? 2 : 1
        , styles := { bold: {value: 700, offset: 16, size: "Int"}
                    , italic: {value: 1, offset: 20, size: "Char"}
                    , underline: {value: 1, offset: 21, size: "Char"}
                    , strikeout: {value: 1, offset: 22, size: "Char"} }

   hDC := DllCall("GetDC", Ptr, hwnd, Ptr)
   VarSetCapacity(LOGFONT, 28 + 32 * mult, 0)
   height := -DllCall("MulDiv", Int, FontSize, Int, DllCall("GetDeviceCaps", Ptr, hDC, Int, LOGPIXELSY), Int, 72)
   NumPut(height, LOGFONT, "Int")
   
   Loop, parse, FontStyle, %A_Space%
      if obj := styles[A_LoopField]
         NumPut(obj.value, &LOGFONT + obj.offset, obj.size)
      
   NumPut(ANTIALIASED_QUALITY, &LOGFONT + 26, "Char")
   StrPut(FontName, &LOGFONT + 28, StrLen(FontName) * mult, A_IsUnicode ? "UTF-16" : "CP0")
   hFont := DllCall("CreateFontIndirect", Ptr, &LOGFONT, Ptr)
   
   DllCall("SetBkMode", Ptr, hDC, Int, TRANSPARENT)
   prevObj := DllCall("SelectObject", Ptr, hDC, Ptr, hFont, Ptr)
   DllCall("SetTextColor", Ptr, hDC, Int64, FontColorBGR)
   DllCall("TextOut", Ptr, hDC, Int, x, Int, y, Str, text, Int, StrLen(text))
   DllCall("SelectObject", Ptr, hDC, Ptr, prevObj, Ptr)
   DllCall("ReleaseDC", Ptr, hwnd, Ptr, hDC)
   DllCall("DeleteObject", Ptr, hFont)
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

69

Re: AHK: графика

Да, работает. А для обычных окон существует подобное?

70

Re: AHK: графика

Функцию DrawTextInAnyWindow() можно применить для любого окна. Другое дело, что текст не во всех окнах будет показываться, он там находится до ближайшей перерисовки. Для примера можно просто заменить cmd на notepad, или на что-то ещё.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

71

Re: AHK: графика

Да, я сразу попробовал. Даже на рабочем столе рисует, но пропадает.
Есть шанс переделать так, чтобы выводилось несколько разных сообщений, чтобы отслеживалось состояние, перерисовывалось содержимое, сдвигалось с окном, и при этом не мигало и комп не грузило?

72

Re: AHK: графика

С окном и сейчас двигается. Как отслеживать состояние — нет мыслей. По идее нужно отслеживать перерисовку окна, но на AHK это, вроде, нереализуемо. И в любом случае при перерисовке будет мигание.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

73

Re: AHK: графика

teadrinker пишет:

Убедитесь в наличии gdiplus.dll в вашей системе!

Насколько я понимаю, для нормальной работы этого скрипта gdiplus.dll должен быть специальный? Я скачал вот отсюда: https://github.com/tariqporter/Gdip/ , но не знаю где он должен находиться в Win10 x64?  Я нашёл несколько уже имеющихся штук, но папки все какие-то странные вроде C:\Windows\WinSxS\x86_microsoft.windows.gdiplus_xxxxxx_none_xxxxxxxx\GdiPlus.dll.
Куда этот скачанный перенести?

74

Re: AHK: графика

Файл GDIplus.dll отсутствует только в ОС старше XP. Чтобы проверить его наличие, выполните код

If !pToken := Gdip_Startup()
MsgBox, 48, Ошибка GDI+, Убедитесь в наличии gdiplus.dll в вашей системе!

У меня в XP этот файл встречается три раза:
C:\WINDOWS\WinSxS\x86_Microsoft.Windows.GdiPlus_6595b64144ccf1df_1.0.0.0_x-ww_8d353f13\GdiPlus.dll
C:\WINDOWS\WinSxS\x86_Microsoft.Windows.GdiPlus_6595b64144ccf1df_1.0.2600.2180_x-ww_522f9f82\GdiPlus.dll
C:\WINDOWS\WinSxS\x86_Microsoft.Windows.GdiPlus_6595b64144ccf1df_1.0.2600.5512_x-ww_dfb54e0c\GdiPlus.dll
Все три файла имеют разный размер. Но скрипт ругается только если переименовать третий файл.

75

Re: AHK: графика

Foma, а что, у вас с тем файлом, что есть в системе, что-то не работает?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg