oGDIp V3 – object-based GDI+ wrapper

Post your working scripts, libraries and tools for AHK v1.1 and older
mcl
Posts: 357
Joined: 04 May 2018, 16:35

oGDIp V3 – object-based GDI+ wrapper

Post by mcl » 22 Nov 2020, 10:21

Updated (2021.08.03):

OGdip − object-based GDI+ wrapper for AutoHotKey v1.1, oriented on ease of use.
Suits for quick-and-dirty prototyping, creating and manipulating images.

Inside the code there are moderately descriptive comments for most classes, methods and properties.
Included examples allow to examine and play with the basics of Image, Bitmap, Pen, Brush, and text functions.

3000+ SLOC, over 450 of 620 functions covered (most of excluded functions are just integer-typed counterparts of already implemented float-typed function.)

Other features:
• Basic screen capture;
• Color and Font selection dialogs.
• Most functions are Localized, to suppress LocalSameAsGlobal #Warning messages.
• Some class methods support chaining, for example:

Code: Select all

myGraphics.SetPen(pen1).SetBrush(br1).DrawRectangle(10,10, 100,50).DrawLine(10,10, 100,50)
Many thanks to all members of AHK community, especially:
GeekDude, iseahound, justme, mikeyww, neogna2, robodesign, Rseding91, SKAN, tic and lexikos.

Github: https://github.com/mcl-on-github/oGdip.ahk
Attachments
oGDIP_v3.0.3.zip
(210.13 KiB) Downloaded 127 times
Last edited by mcl on 28 Aug 2021, 06:09, edited 6 times in total.
robodesign
Posts: 934
Joined: 30 Sep 2017, 03:59
Location: Romania
Contact:

Re: oGDIp

Post by robodesign » 22 Nov 2020, 11:38

Impressive work! Very well written. I like it!

What is channel rms value? In histograms.

Best regards, Marius.
-------------------------
KeyPress OSD v4: GitHub or forum. (presentation video)
Quick Picto Viewer: GitHub or forum.
AHK GDI+ expanded / compilation library (on GitHub)
My home page.
mcl
Posts: 357
Joined: 04 May 2018, 16:35

Re: oGDIp

Post by mcl » 22 Nov 2020, 13:52

robodesign wrote:
22 Nov 2020, 11:38
What is channel rms value? In histograms.
Thanks. RMS = root mean square = sqrt(a²+b²+c²+…).
But in most images there are too many zeroes and 0xFFs to actually use something else than Max.
github://oGDIp - GDI+ wrapper for AHK v1.1
mcl
Posts: 357
Joined: 04 May 2018, 16:35

Re: oGDIp V3 – object-based GDI+ wrapper

Post by mcl » 03 Aug 2021, 12:59

Updated: new version, completely rewritten from scratch, better class hierarchy, covers ≈95% of GDI+ API. See first post.
Dang, it took so long that AHKv2 is already in beta!
github://oGDIp - GDI+ wrapper for AHK v1.1
robodesign
Posts: 934
Joined: 30 Sep 2017, 03:59
Location: Romania
Contact:

Re: oGDIp V3 – object-based GDI+ wrapper

Post by robodesign » 03 Aug 2021, 17:53

Awesome work! Thank you for the work!

Does it cover all of the functions I covered in my GDI+ library edition?

Thank you.

Best regards, Marius.
-------------------------
KeyPress OSD v4: GitHub or forum. (presentation video)
Quick Picto Viewer: GitHub or forum.
AHK GDI+ expanded / compilation library (on GitHub)
My home page.
User avatar
SpeedMaster
Posts: 494
Joined: 12 Nov 2016, 16:09

Re: oGDIp V3 – object-based GDI+ wrapper

Post by SpeedMaster » 03 Aug 2021, 20:14

Thanks for this very impressive work. :shock: :thumbup:

it reminds me of the gaming library "canvas.ahk" from Uberi. 8-) This library also uses GDI class object but it is more suitable for creating games. This library was written a long time ago and still works very well.
The canvas library uses a completely different architecture than yours, maybe you can get some interesting ideas from it. :roll:

https://github.com/Uberi/Canvas-AHK

Canvas.ahk basic usage:

Code: Select all

#SingleInstance force

; https://github.com/Uberi/Canvas-AHK
#include canvas.ahk 

gui, add, text, w550 h550 x10 y10 hwndMainBox border,       ;create a container control for ex. a gui text control and specify the hwnd name for ex. hwndMy_container_box


gui, add, edit, w100 h30 x15 y+10 border, edit text
gui, add, button, xp y+10, button

sf := new Canvas.Surface(550,550) 		;create a new drawing area
sf.Clear(0xFFA0A0A0)                    ;clear the area sf and color it with grey
sf.Smooth := "Best"                     ;antialiasing (improves the image rendering) .Smooth := "None" "Good" or "Best"

Gui, +LastFound
vp := new Canvas.Viewport(MainBox).Attach(sf)   ; attach the drawing area (sf) to the control text (MainBox)

; create pens for drawing
RedPenThin := new Canvas.Pen(0xFFFF0000,5)            ; Pen(ARGB Color, thickness)
RedPenBold := new Canvas.Pen(0xFFFF0000,1)            ; Pen(ARGB Color, thickness)
GreenPen := new Canvas.Pen(0xFF00FF00,1)
PurplePen:= new Canvas.Pen(0xFF800080,1)
YellowPen := new Canvas.Pen(0x80FFFF00,3)			  ; this one has a transparency set to 80
AquaPen:= new Canvas.Pen(0xFF00FFFF,1)

; create some brushes (to use only with filled forms)
GreenBrush:= new Canvas.Brush(0xAA00FF00)			; this brush has a transparency set to AA
BrownBrush:= new Canvas.Brush(0xFFA52A2A)  			; this bursh is not transparent

sf.DrawRectangle(RedPenBold,10,10,277,50)           		;DrawRectangle(pen,posx,posy,Width,Height)
sf.DrawRectangle(RedPenThin,10,80,100,75)          			;DrawRectangle(pen,posx,posy,Width,Height)
sf.FillRectangle(GreenBrush,20,145,50,50)            		;FillRectangle(brush,posx,posy,Width,Height) 
sf.DrawEllipse(PurplePen,10,210,100,50)                   	;DrawEllipse(pen,posx,posy,Width,Height)
sf.FillEllipse(BrownBrush,10,280,50,50)                   	;Draw a circle
sf.Line(AquaPen,10,350,300,290)       						;draw a line Line(Pen,x1,y1,x2,y2)
sf.DrawPolygon(PurplePen,[[30,400],[30,500],[100,500]])		;draw a polygon (triangle)

gui, +resize
gui, color, green
gui, show, w700 h700 

return
guiclose: 
esc:: 
exitapp 
return
P.S. the examples you provided are a bit too complex for me. :?
Maybe you can provide some basic examples for beginners. 8-)

Cheers
mcl
Posts: 357
Joined: 04 May 2018, 16:35

Re: oGDIp V3 – object-based GDI+ wrapper

Post by mcl » 04 Aug 2021, 14:48

robodesign wrote: Does it cover all of the functions I covered in my GDI+ library edition?
Thanks, Marius! Your library was a huge inspiration for me, I learned a lot from it.
All GdiPlus-based functions − yes, they are all in there. However, this library lacks almost all of pure GDI functions (like CreateDIBSection or UpdateLayeredWindow − there just wasn't good place to fit them). Another major difference is the absence of MCode-based functions, especially BlendBitmaps; I have a .dll prototype written in C as a replacement, but it's not public-worthy yet.

SpeedMaster wrote: it reminds me of the gaming library "canvas.ahk" from Uberi. 8-) This library also uses GDI class object but it is more suitable for creating games.

P.S. the examples you provided are a bit too complex for me.
Maybe you can provide some basic examples for beginners.
Thanks for reply!
This library have other goals, and therefore, different approach than Canvas.
I rewrote your example and added few comments to explain some differences. Hope this helps.
OGdip basic example
Also, thanks once more − I found some bugs while writing an example. Updated version is in the first post.
github://oGDIp - GDI+ wrapper for AHK v1.1
robodesign
Posts: 934
Joined: 30 Sep 2017, 03:59
Location: Romania
Contact:

Re: oGDIp V3 – object-based GDI+ wrapper

Post by robodesign » 04 Aug 2021, 16:35

mcl wrote:
04 Aug 2021, 14:48
robodesign wrote: Does it cover all of the functions I covered in my GDI+ library edition?
Thanks, Marius! Your library was a huge inspiration for me, I learned a lot from it.
All GdiPlus-based functions − yes, they are all in there. However, this library lacks almost all of pure GDI functions (like CreateDIBSection or UpdateLayeredWindow − there just wasn't good place to fit them). Another major difference is the absence of MCode-based functions, especially BlendBitmaps; I have a .dll prototype written in C as a replacement, but it's not public-worthy yet.
Looking forward to the DLL version of that.

Have you seen I have a DLL in QPV? It has blending modes and alpha masking related functions. Maybe you'll find it interesting to look at the source (c++).

And yes, good choice not to include pure GDI functions in the library. For the sake of compatibility I kept them in.

I made my own GDI library, but I did not yet publish as standalone, but it can be found in the QPV source code.

Today I went through almost every line of code in your library... I have two suggestions:

1. Provide more examples of how to call the different class methods.
2. There's no possibility of error handling. No GDI+ error codes or anything like that.

In real world scenarios, one may need this.

In my GDI+ library edition I hacked up something to this end... It's not good enough.. (see QPV source code).

My suggestion is you try implementing something for error handling.

Best regards, Marius.
-------------------------
KeyPress OSD v4: GitHub or forum. (presentation video)
Quick Picto Viewer: GitHub or forum.
AHK GDI+ expanded / compilation library (on GitHub)
My home page.
User avatar
SpeedMaster
Posts: 494
Joined: 12 Nov 2016, 16:09

Re: oGDIp V3 – object-based GDI+ wrapper

Post by SpeedMaster » 05 Aug 2021, 08:30

mcl wrote: I rewrote your example and added few comments to explain some differences. Hope this helps.
This is exactly what I was looking for. Thanks for the commented example, it will help me get started. :thumbup:

I know that this library is not made for game creation but maybe there is a way to make a shape move.
Here is an example with canvas. (use the arrow cursors to move a yellow dot) :think:
Spoiler
cheers
Last edited by SpeedMaster on 09 Aug 2021, 16:50, edited 1 time in total.
tuzi
Posts: 223
Joined: 27 Apr 2016, 23:40

Re: oGDIp V3 – object-based GDI+ wrapper

Post by tuzi » 09 Aug 2021, 10:48

amazing work!
amazing demo!
neogna2
Posts: 590
Joined: 15 Sep 2016, 15:44

Re: oGDIp V3 – object-based GDI+ wrapper

Post by neogna2 » 11 Aug 2021, 14:02

@mcl I get a "The selected attachment does not exist anymore" error. Did you take it down while updating? If not then maybe an error cause by recent forum issues?
mcl
Posts: 357
Joined: 04 May 2018, 16:35

Re: oGDIp V3 – object-based GDI+ wrapper

Post by mcl » 11 Aug 2021, 23:18

neogna2 wrote: I get a "The selected attachment does not exist anymore" error. Did you take it down while updating? If not then maybe an error cause by recent forum issues?
Thanks for pointing out. Reattached, should be working now.
github://oGDIp - GDI+ wrapper for AHK v1.1
neogna2
Posts: 590
Joined: 15 Sep 2016, 15:44

Re: oGDIp V3 – object-based GDI+ wrapper

Post by neogna2 » 16 Aug 2021, 13:01

@mcl Thank you for this massive class and for the examples to help us get started.

Example_Metafile.ahk does not create the Example.emf file for me, despite what the MsgBox says.

Some of your examples have the line
Gui, +E0x02000000 ; WS_EX_COMPOSITED - reduces flicker on bitmap reloading
I still got flickering when toying around with code that redraws the bitmap very frequently. The double buffer method removed the flickering.
Gui, +E0x02000000 +E0x00080000 ; WS_EX_COMPOSITED & WS_EX_LAYERED => Double Buffer
mcl
Posts: 357
Joined: 04 May 2018, 16:35

Re: oGDIp V3 – object-based GDI+ wrapper

Post by mcl » 18 Aug 2021, 15:32

neogna2 wrote: Example_Metafile.ahk does not create the Example.emf file for me, despite what the MsgBox says.
Thanks for reply and for the tip about double buffering.
In tenth or eleventh iteration of rewriting I forgot to put back safeguard for that case.
Try wrapping constructor in Example_Metafile.ahk into these lines:

Code: Select all

; Start recording metafile. Note that it uses non-standard constructor!
tempHDC := DllCall("CreateCompatibleDC", "Ptr", 0, "Ptr")
mf := OGdip.Metafile.RecordTo(tempHDC, "Example.emf",, [0, 0, 3*260, 3*100], "Pixel")
DllCall("DeleteDC", "Ptr", tempHDC)
I know about few other issues with the lib, but unfortunately I don't have time right now to fix them.
github://oGDIp - GDI+ wrapper for AHK v1.1
mcl
Posts: 357
Joined: 04 May 2018, 16:35

Re: oGDIp V3 – object-based GDI+ wrapper

Post by mcl » 28 Aug 2021, 06:22

Updated (2021.08.28):
  • GitHub repo is now a thing: https://github.com/mcl-on-github/oGdip.ahk; (I have no clue what to do with it tho')
  • Fixed .MixRGB();
  • Fixed .Screenshot("*") now properly captures all monitors instead of window with asterisk in the title.
  • Fixed Metafile.RecordTo(0, ...) now creates temporary DC (thanks neogna2);
  • Fixed loading properties list from the same folder as ogdip.ahk;
  • Updated double-buffering in examples (thanks neogna2);
github://oGDIp - GDI+ wrapper for AHK v1.1
User avatar
SpeedMaster
Posts: 494
Joined: 12 Nov 2016, 16:09

Re: oGDIp V3 – object-based GDI+ wrapper

Post by SpeedMaster » 11 Nov 2021, 13:50

SpeedMaster wrote:
05 Aug 2021, 08:30
I know that this library is not made for game creation but maybe there is a way to make a shape move. :think:
Maybe like this with oGDIp ... :eh:

(use the arrow cursors or buttons to move a yellow dot)

Code: Select all

#SingleInstance force
#include OGdip.ahk
OGdip.Startup()  ; This function initializes GDI+ and must be called first.


; Create GUI container for our drawings. 'Text' will work too, but semantically 'Picture' is better.
gui, add, Picture, w550 h550 x10 y10 hwndMainBox Border


bmp := new OGdip.Bitmap(550,550)  ; Create new empty Bitmap with given width and height
                                  ; .G refers to Graphics surface of this Bitmap, it's used to draw things
bmp.G.Clear(0xFFA0A0A0)           ; Clear fills bitmap with single color.
bmp.G.SetOptions({smooth:2})      ; Sets high-quality antialiasing

Gui, +LastFound

; OGdip doesn't provide any method similar to .Attach, to avoid unnecessary redraws.
; We'll put drawn image manually later.

; create pens for drawing
RedPenThin := new OGdip.Pen(0xFFFF0000,5)  ; Pen(ARGB Color, thickness)
RedPenBold := new OGdip.Pen(0xFFFF0000,1)  ; Pen(ARGB Color, thickness)
GreenPen   := new OGdip.Pen(0xFF00FF00,1)
PurplePen  := new OGdip.Pen(0xFF800080,1)
YellowPen  := new OGdip.Pen(0x80FFFF00,3)  ; this one has a transparency set to 80
AquaPen    := new OGdip.Pen(0xFF00FFFF,1)

; create some brushes (to use only with filled forms)
GreenBrush:= new OGdip.Brush(0xAA00FF00)  ; this brush has a transparency set to AA
BrownBrush:= new OGdip.Brush(0xFFA52A2A)  ; this bursh is not transparent
YellowBrush:= new OGdip.Brush(0xaaFFFF00)

; In OGdip, we need to set Pen or Brush first, then draw some figures.
; Every .G.Draw method tries to both stroke the figure with Pen, and fill it with Brush, there is no separate .Draw/.Fill methods
; Most methods of .G can be chained together in one line:
bmp.G.SetPen(RedPenBold).DrawRectangle(10,10,277,50)
bmp.G.SetPen(RedPenThin).DrawRectangle(10,80,100,75)

; Green rectangle in original example do not have pen strokes.
; We can remove previously set Pen with empty string:
bmp.G.SetPen("").SetBrush(GreenBrush)
bmp.G.DrawRectangle(20,145,50,50)  ;FillRectangle

; Switching tools may seem excessive in this example, I admit, but there is a logic behind it.
; For instance, if you need to draw many lines with single pen, you have to specify it only once.
bmp.G.SetPen(PurplePen).SetBrush("")
bmp.G.DrawEllipse(10,210,100,50)                                 ; .DrawEllipse(posx,posy,Width,Height)
bmp.G.SetPen("").SetBrush(BrownBrush).DrawEllipse(10,280,50,50)  ; Also try .DrawEllipseC( centerX, centerY, radiusX [, radiusY] )
bmp.G.SetPen(AquaPen).DrawLine(10,350,300,290)                   ; Draw a line (lines don't use brush, because they aren't closed.)

; You can use array of arrays for polygon, but you don't have to:
; plain numbers or arrays of coords, or mix of both will work too.
bmp.G.SetPen(PurplePen).SetBrush("")
bmp.G.DrawPolygon([[30,400],[30,500],[100,500]])  ; Draw a polygon (triangle)

; Now image can be drawn into Picture control.
; You can also use control name, like "Static1"
bmp.SetToControl(MainBox)

sf_background := new OGdip.Bitmap(550,550)	  ;  clone the current bitmap
sf_background.G.DrawImage(bmp)       ; draw the bmp on it			

gui, add, button , gup, move up
gui, add, button , x+10 yp gdown, move down
gui, add, button , x+10 yp  gleft, move left
gui, add, button , x+10 yp  gright, move right

Gui, +E0x02000000 +E0x00080000 ; WS_EX_COMPOSITED & WS_EX_LAYERED => Double Buffer
gui, +Resize
gui, color, green
gui, Show, w700 h700 

x:=y:=0 ; translation position of the moving spot

return
guiclose: 
esc:: 
bmp := ""
OGdip.Shutdown()  ; It's probably not necessary, but it's a good manners to delete all objects and shutdown GDI+ properly.
exitapp 
return

right:: x += 10, bmp.G.Clear(0xFFFFFF00).DrawImage(sf_background), state:=bmp.G.SaveState(), bmp.G.TransformMove(x, y).SetPen("").SetBrush(YellowBrush).DrawEllipse(200,280,50,50).RestoreState(state), bmp.SetToControl(MainBox)
left::  x -= 10, bmp.G.Clear(0xFFFFFF00).DrawImage(sf_background), state:=bmp.G.SaveState(), bmp.G.TransformMove(x, y).SetPen("").SetBrush(YellowBrush).DrawEllipse(200,280,50,50).RestoreState(state), bmp.SetToControl(MainBox)
up::    y -= 10, bmp.G.Clear(0xFFFFFF00).DrawImage(sf_background), state:=bmp.G.SaveState(), bmp.G.TransformMove(x, y).SetPen("").SetBrush(YellowBrush).DrawEllipse(200,280,50,50).RestoreState(state), bmp.SetToControl(MainBox)
down::  y += 10, bmp.G.Clear(0xFFFFFF00).DrawImage(sf_background), state:=bmp.G.SaveState(), bmp.G.TransformMove(x, y).SetPen("").SetBrush(YellowBrush).DrawEllipse(200,280,50,50).RestoreState(state), bmp.SetToControl(MainBox)

However there is no push() or pop() methods like in Canvas but I tried to get similar result
KelvinK
Posts: 1
Joined: 11 Nov 2021, 16:22

Re: oGDIp V3 – object-based GDI+ wrapper

Post by KelvinK » 11 Nov 2021, 16:31

Hi.

Thank you for sharing this. I have little experience with both OOP and utilizing function libraries in AutoHotkey, so I will have to figure out how to use this first.

But before that, I was wondering if it would allow me to do the following:

1. Render invisible/blank canvas
2. Allow the canvas to display an animated gif
3. Allow transparency changes to the gif

The point is to display an animated image that has no background.

Thanks in advance.
SOTE
Posts: 1426
Joined: 15 Jun 2015, 06:21

Re: oGDIp V3 – object-based GDI+ wrapper

Post by SOTE » 12 Nov 2021, 05:47

robodesign wrote:
03 Aug 2021, 17:53
Awesome work! Thank you for the work!
I agree about this, and thanks mcl. Great to see various GDI options.
robodesign wrote:
03 Aug 2021, 17:53
Does it cover all of the functions I covered in my GDI+ library edition?
I see that you have been keeping your GDI+ library up to date (including AHK 1.1 and AHK 2 versions). I noticed because I primarily use functions. I think you should also post your updates on Scripts and Functions too. This way people have more obvious options to choose from. The work that both you and mcl are doing is very helpful.
robodesign
Posts: 934
Joined: 30 Sep 2017, 03:59
Location: Romania
Contact:

Re: oGDIp V3 – object-based GDI+ wrapper

Post by robodesign » 12 Nov 2021, 12:29

SOTE wrote:
12 Nov 2021, 05:47
robodesign wrote:
03 Aug 2021, 17:53
Awesome work! Thank you for the work!
I agree about this, and thanks mcl. Great to see various GDI options.
robodesign wrote:
03 Aug 2021, 17:53
Does it cover all of the functions I covered in my GDI+ library edition?
I see that you have been keeping your GDI+ library up to date (including AHK 1.1 and AHK 2 versions). I noticed because I primarily use functions. I think you should also post your updates on Scripts and Functions too. This way people have more obvious options to choose from. The work that both you and mcl are doing is very helpful.
Thank you . I am doing my best. I hope you saw I also published a GDI library.

Please note, the GDI+ library is not updated entirely for v2 - to latest betas. I have not yet begun the work on that...
-------------------------
KeyPress OSD v4: GitHub or forum. (presentation video)
Quick Picto Viewer: GitHub or forum.
AHK GDI+ expanded / compilation library (on GitHub)
My home page.
tuzi
Posts: 223
Joined: 27 Apr 2016, 23:40

Re: oGDIp V3 – object-based GDI+ wrapper

Post by tuzi » 15 Nov 2021, 20:58

so cool!

thank you for share it!
Post Reply

Return to “Scripts and Functions (v1)”