
Please may I enquire, what is big difference between GDI & GDI+? I am guessing hBitmap and pBitmap are nearly same data bandwidth size... but one is higher quality? I don't understand.
but Thank you, it worked!
#SingleInstance, Force #NoEnv DetectHiddenWindows, On CoordMode, Mouse, Screen SetBatchLines, -1 SetWinDelay, 0 SetWorkingDir %A_ScriptDir% OnExit, Exit ; Uncomment if Gdip.ahk is not in your standard library ;#Include, Gdip.ahk If !pToken := Gdip_Startup() { MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system ExitApp } pBrush := Gdip_BrushCreateSolid(0x3300ff00), pPen := Gdip_CreatePen(0xbbff2233, 1) Gui, 1: +AlwaysOnTop -Caption +ToolWindow +Border Gui, 1: Margin, 0, 0 Gui, 1: Add, Picture, x0 y0 w50 h50 0xE hwndPic Gui, 1: Show, AutoSize Hotkey, ^LButton, Drag, On Return ;######################################################################################## Drag: Gui, 1: Submit, NoHide MouseGetPos, x1, y1 Gui, 2: -Caption +E0x80000 +LastFound +AlwaysOnTop +ToolWindow +OwnDialogs hwnd2 := WinExist() Gui, 2: Show, NA Loop { Sleep, 50 If !GetKeyState("LButton", "P") Break MouseGetPos, x2, y2 If (x2 = Oldx2) && (y2 = Oldy2) Continue If (x2 >= x1) && (y2 <= y1) x := x1, y := y2, w := x2-x1, h := y1-y2 Else If (x2 >= x1) && (y2 >= y1) x := x1, y := y1, w := x2-x1, h := y2-y1 Else If (x2 <= x1) && (y2 >= y1) x := x2, y := y1, w := x1-x2, h := y2-y1 Else If (x2 <= x1) && (y2 <= y1) x := x2, y := y2, w := x1-x2, h := y1-y2 Oldx2 := x2, Oldy2 := y2 hbm := CreateDIBSection(w, h), hdc := CreateCompatibleDC(), obm := SelectObject(hdc, hbm), G := Gdip_GraphicsFromHDC(hdc) Gdip_FillRectangle(G, pBrush, 0, 0, w, h) Gdip_DrawRectangle(G, pPen, 0, 0, w-1, h-1) UpdateLayeredWindow(hwnd2, hdc, x, y, w, h) Gdip_DeleteGraphics(G), SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc) } Gui, 2: Destroy pBitmap1 := Gdip_BitmapFromScreen(x "|" y "|" w "|" h) pBitmap2 := Gdip_CreateBitmap(1, 1), G2 := Gdip_GraphicsFromImage(pBitmap2) pBitmap3 := Gdip_CreateBitmap(50, 50), G3 := Gdip_GraphicsFromImage(pBitmap3) Gdip_DrawImage(G2, pBitmap1, 0, 0, 1, 1, 0, 0, 50, 50) Gdip_FillRectangle(G3, pBrush2 := Gdip_BrushCreateSolid(Gdip_GetPixel(pBitmap2, 0, 0)), 0, 0, 50, 50) hBitmap := Gdip_CreateHBITMAPFromBitmap(pBitmap3) SetImage(Pic, hBitmap) Gdip_DeleteBrush(pBrush2) Gdip_DisposeImage(pBitmap1), Gdip_DisposeImage(pBitmap2), Gdip_DisposeImage(pBitmap3) Gdip_DeleteGraphics(G2), Gdip_DeleteGraphics(G3) DeleteObject(hBitmap) Return ;######################################################################################## Exit: Gdip_DeleteBrush(pBrush), Gdip_DeletePen(pPen) Gdip_Shutdown(pToken) ExitApp Return
Why can't I use your code to save a transparent PNG?but with 3 extra lines (one of them used to dispose of the pBitmap created), allowing us to save a gdi bitmap to disk
#SingleInstance, Force #NoEnv DetectHiddenWindows, On CoordMode, Mouse, Screen SetBatchLines, -1 SetWinDelay, 0 SetWorkingDir %A_ScriptDir% ; Uncomment if Gdip.ahk is not in your standard library ;#Include, Gdip.ahk If !pToken := Gdip_Startup() { MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system ExitApp } Width := 200, Height := 200 Gui, 1: -Caption +E0x80000 +LastFound +AlwaysOnTop +ToolWindow +OwnDialogs Gui, 1: Show, NA hwnd1 := WinExist() pBitmap := Gdip_CreateBitmap(Width, Height), Gp := Gdip_GraphicsFromImage(pBitmap) pBrush := Gdip_BrushCreateSolid(0x77ff0000) Gdip_FillRectangle(Gp, pBrush, Width//4, Height//4, Width//2, Height//2) hbm := CreateDIBSection(Width, Height), hdc := CreateCompatibleDC(), obm := SelectObject(hdc, hbm), Gh := Gdip_GraphicsFromHDC(hdc) Gdip_DrawImage(Gh, pBitmap, 0, 0, Width, Height) UpdateLayeredWindow(hwnd1, hdc, (A_ScreenWidth-Width)//2, (A_ScreenHeight-Height)//2, Width, Height) Gdip_SaveBitmapToFile(pBitmap, "file.png") Gdip_DeleteBrush(pBrush) Gdip_DisposeImage(pBitmap) SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc) Gdip_DeleteGraphics(Gp), Gdip_DeleteGraphics(Gh) Gdip_Shutdown(pToken) Return
hbm := CreateDIBSection(Width, Height), hdc := CreateCompatibleDC(), obm := SelectObject(hdc, hbm), Gh := Gdip_GraphicsFromHDC(hdc)
Gdip_DrawImage(Gh, pBitmap, 0, 0, Width, Height)
Have you tried painting everything onto the bitmap, then painting the bitmap onto the screen? As an added benefit, the image is presented to the screen in a single drawing operation. This usually eliminates any flicker that may be present.I've found no way of just copying and updating the changed area, so my final solution was painting everything twice, once on the screen and once on the bitmap.
; Get a device context from a Graphics object: DllCall("gdiplus\GdipGetDC", "uint", pGraphics, "uint*", hdc) ; Release the device context before using the Graphics object again: DllCall("gdiplus\GdipReleaseDC", "uint", pGraphics, "uint", hdc) ; Get a Graphics object from a window handle: DllCall("gdiplus\GdipCreateFromHWND", hwnd, "uint*", pGraphics)
Gdip_FillPolygon(pGraphics, pBrush, "0,0|100,0|100,100|0,100|0,0")
; gdi+ ahk tutorial 1 written by tic (Tariq Porter) ; Requires Gdip.ahk either in your Lib folder as standard library or using #Include ; ; Tutorial to draw a single ellipse and rectangle to the screen #SingleInstance, Force #NoEnv SetBatchLines, -1 ; Uncomment if Gdip.ahk is not in your standard library #Include, Gdip.ahk ; Start gdi+ If !pToken := Gdip_Startup() { MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system ExitApp } OnExit, Exit ; Set the width and height we want as our drawing area, to draw everything in. This will be the dimensions of our bitmap Width := 800, Height := 800 ; Create a layered window (+E0x80000 : must be used for UpdateLayeredWindow to work!) that is always on top (+AlwaysOnTop), has no taskbar entry or caption Gui, 1: -Caption +E0x80000 +LastFound +AlwaysOnTop +ToolWindow +OwnDialogs ; Show the window Gui, 1: Show, NA ; Get a handle to this window we have created in order to update it later hwnd1 := WinExist() ; Create a gdi bitmap with width and height of what we are going to draw into it. This is the entire drawing area for everything hbm := CreateDIBSection(Width, Height) ; Get a device context compatible with the screen hdc := CreateCompatibleDC() ; Select the bitmap into the device context obm := SelectObject(hdc, hbm) ; Get a pointer to the graphics of the bitmap, for use with drawing functions G := Gdip_GraphicsFromHDC(hdc) ; Set the smoothing mode to antialias = 4 to make shapes appear smother (only used for vector drawing and filling) Gdip_SetSmoothingMode(G, 4) pBrush := Gdip_BrushCreateSolid(0x660000ff) Gdip_FillUniformPolygon(G, pBrush, 9, 100, 100, 50) Gdip_DeleteBrush(pBrush) ; Update the specified window we have created (hwnd1) with a handle to our bitmap (hdc), specifying the x,y,w,h we want it positioned on our screen ; So this will position our gui at (0,0) with the Width and Height specified earlier UpdateLayeredWindow(hwnd1, hdc, 0, 0, Width, Height) ; Select the object back into the hdc SelectObject(hdc, obm) ; Now the bitmap may be deleted DeleteObject(hbm) ; Also the device context related to the bitmap may be deleted DeleteDC(hdc) ; The graphics may now be deleted Gdip_DeleteGraphics(G) Return ;####################################################################### Gdip_FillUniformPolygon(pGraphics, pBrush, Sides, x, y, Length, FillMode=0) { a := 0, Points := x "," y "|" Loop, %Sides% { x += Length*Cos(a), y += Length*Sin(a) Points .= x "," y "|" a += ((4*ATan(1))/180)*(360/Sides) } StringTrimRight, Points, Points, 1 Gdip_FillPolygon(pGraphics, pBrush, Points, FillMode) } ;####################################################################### Exit: ; gdi+ may now be shutdown on exiting the program Gdip_Shutdown(pToken) ExitApp Return
Gdip_FillUniformPolygon(pGraphics, pBrush, Sides, x, y, w, h, FillMode=0)
Of course: Gdip_GraphicsFromHDC has nothing to do with creating a bitmap. If you had already created a GDI+ bitmap and wanted to draw it onto the screen, you could use Gdip_GraphicsFromHDC to create a Graphics object to wrap the screen hdc. Whether or not the bitmap is transparent is irrelevant. If you create a 32-bit ARGB GDI+ bitmap, it should be transparent by default. It only becomes opaque when you draw an opaque image onto it or fill it with an opaque colour. For instance, in your script posted at donationcoder.com:@ Lexicos: I can't get Gdip_GraphicsFromHDC to create a transparent bitmap.
hBrush:= Gdip_BrushCreateSolid("0xFF" background) ; <- This is an opaque/solid brush. Gdip_FillRectangle(pGraphic3, hBrush, 0, 0, width3, height3) Gdip_DeleteBrush(hBrush)
Gdip_GraphicsFromHDC has nothing to do with creating a bitmap
E := DllCall("gdiplus\GdipSaveImageToFile", "UInt", pBitmap, "UInt", &wOutput, "UInt", pCodec, "UInt", 0)There's an additional argument that this can be called with, which can set the jpg quality, however I'm unsure how to build the "tParams" argument.