Thank you !
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!
GDI+ standard library 1.45 by tic
Started by
tic
, May 28 2008 02:27 AM
1385 replies to this topic
#31
-
Posted 15 July 2008 - 07:18 PM
Due to an interesting request by infogulch:
Get avg color of portion of the screen
A small gui will appear in the centre of the screen. You can then drag a selection of the screen using ctrl and lbutton. it will then update the gui with the average of the colours almost instantly. Obviously not all of the code below is needed, but i just wanted to make it look nice and easy to use
Ensure you have version 1.17 from the 1st post
Get avg color of portion of the screen
A small gui will appear in the centre of the screen. You can then drag a selection of the screen using ctrl and lbutton. it will then update the gui with the average of the colours almost instantly. Obviously not all of the code below is needed, but i just wanted to make it look nice and easy to use
Ensure you have version 1.17 from the 1st post
#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
#32
-
Posted 17 July 2008 - 03:46 PM
@tic:
I have no problem saving a transparent PNG when it's created using pBitmap:=Gdip_CreateBitmap(width,height)
Skrommel
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
I have no problem saving a transparent PNG when it's created using pBitmap:=Gdip_CreateBitmap(width,height)
Skrommel
#33
-
Posted 18 July 2008 - 12:41 AM
I would suggest that if you are wanting to work with a gdi+ bitmap the entire time, and want to use it to update a gui and save it to disk, then follow this method:
So work with a gdi+ bitmap (pBitmap) the entire time, and then whenever you want to update your gui with whatever you've been doing then just create a gdi bitmap:
and then draw your gdi+ bitmap into the gdi bitmap:
You will then obviously have to dispose of all the extra stuff you created.
But the above example shows how we can use a bitmap with a transparent background and use it to update a gui and save it to disk
Hope that helps
#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
So work with a gdi+ bitmap (pBitmap) the entire time, and then whenever you want to update your gui with whatever you've been doing then just create a gdi bitmap:
hbm := CreateDIBSection(Width, Height), hdc := CreateCompatibleDC(), obm := SelectObject(hdc, hbm), Gh := Gdip_GraphicsFromHDC(hdc)
and then draw your gdi+ bitmap into the gdi bitmap:
Gdip_DrawImage(Gh, pBitmap, 0, 0, Width, Height)
You will then obviously have to dispose of all the extra stuff you created.
But the above example shows how we can use a bitmap with a transparent background and use it to update a gui and save it to disk
Hope that helps
#34
-
Posted 18 July 2008 - 11:38 AM
I've tried similar code, but the problem is speed. It copies and redraws the entire screen instead of just the few changed pixels, so in a drawing app you'll end up with "square" circles and slow response.
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.
Is there no way to convert a DC bitmap into a transparent one, or loading a transparent bitmap into a DC?
Skrommel
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.
Is there no way to convert a DC bitmap into a transparent one, or loading a transparent bitmap into a DC?
Skrommel
#35
-
Posted 19 July 2008 - 06:02 PM
Tic, I want to draw a complex Filled shape with several sides and straight angles. It has no curves. Could you pls start me on some path to understanding how best to draw something simple with multiple sides and angles? One or two demonstrations would be so excellent to get me on my Web feet, if possible
hey, I have really enjoyed working thru your tutorials to understand concepts, and use of the gdip commands This was something I couldn't quite ascertain how to do yet, but would like to
hey, I have really enjoyed working thru your tutorials to understand concepts, and use of the gdip commands This was something I couldn't quite ascertain how to do yet, but would like to
#36
-
Posted 20 July 2008 - 04:29 PM
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.
If the screen is represented by a handle to a device context (hdc), you can use Gdip_GraphicsFromHDC to retrieve a GDI+ Graphics object. The Graphics object should be deleted with Gdip_DeleteGraphics before using any GDI functions with the original hdc.
There are also functions which tic has not yet wrapped:
; 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)
#37
-
Posted 21 July 2008 - 08:17 AM
Skrommel:
I think you are going about it the wrong way. If you are wanting to make a drawing application then you would use a gdi bitmap to let the user draw onto, and update the window with this, and then when they go to save what they have drawn, simpley convert it to a gdi+ bitmap. I do not believe it is necessary to get the graphics of the window. When I get time I'll write a quick start to a drawing app that allows a couple of drawing functions and can have layers if you wish to demonstrate the way I would do it, but I'll have to see when I get some time.
Sunrise:
To fill polygons you would use Gdip_FillPolygon() and you pass the points on the polygon as "x1,y1|x2,y2|x3,y3......"
So a square would look like:
That last coordinate is optional to close the polygon. I will start on a helper function if you wish to allow quick and easy construction of uniform polygons.
Taking the 1st example I have added a simple function to construct these uniform polygons as demonstrated here:
I have not added Gdip_FillUniformPolygon() to the library as I would prefer it to be in the form of:
so rather than specifying the length of each side, you could specify the width and height of the entire polygon, but this will be a bit tricky, so will do it when I have more time. Try the above example and ask if you have any other problems
I think you are going about it the wrong way. If you are wanting to make a drawing application then you would use a gdi bitmap to let the user draw onto, and update the window with this, and then when they go to save what they have drawn, simpley convert it to a gdi+ bitmap. I do not believe it is necessary to get the graphics of the window. When I get time I'll write a quick start to a drawing app that allows a couple of drawing functions and can have layers if you wish to demonstrate the way I would do it, but I'll have to see when I get some time.
Sunrise:
To fill polygons you would use Gdip_FillPolygon() and you pass the points on the polygon as "x1,y1|x2,y2|x3,y3......"
So a square would look like:
Gdip_FillPolygon(pGraphics, pBrush, "0,0|100,0|100,100|0,100|0,0")
That last coordinate is optional to close the polygon. I will start on a helper function if you wish to allow quick and easy construction of uniform polygons.
Taking the 1st example I have added a simple function to construct these uniform polygons as demonstrated here:
; 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
I have not added Gdip_FillUniformPolygon() to the library as I would prefer it to be in the form of:
Gdip_FillUniformPolygon(pGraphics, pBrush, Sides, x, y, w, h, FillMode=0)
so rather than specifying the length of each side, you could specify the width and height of the entire polygon, but this will be a bit tricky, so will do it when I have more time. Try the above example and ask if you have any other problems
#38
-
Posted 21 July 2008 - 11:38 AM
@ Lexikos: I can't get Gdip_GraphicsFromHDC to create a transparent bitmap.
@ tic: I've posted the code at http://www.donationc...19781#msg119781
Skrommel
#39
-
Posted 23 July 2008 - 12:46 AM
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)
#40
-
Posted 23 July 2008 - 06:38 AM
Lexikos wrote:
Sorry, I ment Gdip_GraphicsFromHDC can't be used as a basis for saving a transparent png file, it gets a black backround.
Skrommel
Gdip_GraphicsFromHDC has nothing to do with creating a bitmap
Sorry, I ment Gdip_GraphicsFromHDC can't be used as a basis for saving a transparent png file, it gets a black backround.
Skrommel
#41
-
Posted 24 July 2008 - 12:04 AM
Gdip_GraphicsFromHDC is used to get a GDI+ Graphics object for drawing onto a GDI device context. It does not modify the underlying object of the device context (which may or may not be a bitmap), so it will only "get a black background" if the underlying bitmap already had a black background.
I suggest there is some other issue.
I suggest there is some other issue.
#42
-
Posted 24 July 2008 - 07:29 AM
When saving a .jpg using Gdip_SaveBitmapToFile, is it possible to change the output quality? (0-100 in photoshop, for example)
edit:
I found out it's possible.
From Gdip.ahk
http://bb4w.wikispac...ng a JPEG image
edit:
I found out it's possible.
From Gdip.ahk
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.
http://bb4w.wikispac...ng a JPEG image
#43
-
Posted 24 July 2008 - 10:11 AM
Skrommel:
I think you are going about the problem in slightly the wrong way, and don't think those functions you are adding are necessary. At the weekend I'll write a quick app to show how I think it should be done
thirtydot:
I have not added that yet, but I'll make a modification to that function and release an update to Gdip in the next couple of days
I think you are going about the problem in slightly the wrong way, and don't think those functions you are adding are necessary. At the weekend I'll write a quick app to show how I think it should be done
thirtydot:
I have not added that yet, but I'll make a modification to that function and release an update to Gdip in the next couple of days
#44
-
Posted 24 July 2008 - 10:29 AM