Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

GDI+ standard library 1.45 by tic


  • Please log in to reply
1385 replies to this topic
djvj
  • Members
  • 70 posts
  • Last active: Jul 22 2016 02:54 AM
  • Joined: 19 Sep 2010
Great news (for me)! That script you made tic works perfect in my tests. I can move the image exactly where I want and it stays in place and doesn't bounce around in it's box anymore. I don't need any tricky formulas either, yay. Thanks again.

Oh also why the new script is smoother is because you removed setinterpolation mode. If I put that back in, it gets a little jerky again. Guess this core2duo is feeling a little dated.

sumon
  • Moderators
  • 1317 posts
  • Last active: Dec 05 2016 10:14 PM
  • Joined: 18 May 2010

I modifed the Gdip.ahk file to support all 4 of the main AHK builds: Basic, _L ANSI, _L Unicode x86 and x64. Thanks to fincs for the AHK_L only version of the library that had 64 bit support.

Download >here<

I tested all of the example scripts on the first post and everything worked fine. This doesn't include any of the BRA functions.



Sweet job Rseding91 (and of course Uberi & fincs!)!

tic
  • Members
  • 1934 posts
  • Last active: Dec 21 2015 01:05 PM
  • Joined: 22 Apr 2007

Sweet job Rseding91!


Yep, great job fincs, Rseding91 and Uberi!

I will look through and start thinking about the next GDI+ version and how best to go about it

Thanks all for your contributions!

tic
  • Members
  • 1934 posts
  • Last active: Dec 21 2015 01:05 PM
  • Joined: 22 Apr 2007
So I started thinking a bit about AHK_L and it seems that the bugs I initially had a problem with have now been resolved.
I thought it might be nice to take advantage of this in the GDI+ library. This isn't necessarily how it would look, but just a suggestion, and a small look at using it for the 1st tutorial. The whole code could be reduced to:

#SingleInstance, Force
SetBatchLines, -1

Width := 1400, Height := 1050
Gui, 1: -Caption +E0x80000 +LastFound +AlwaysOnTop +ToolWindow +OwnDialogs
Gui, 1: Show, NA

Gdip := new Gdip(), gw := new Gdip.GDIWin(), brush := new Gdip.Brush()
gw.CreateGDIObj(WinExist(), Width, Height)
brush.CreateBrush("Red255", 0xffff0000), brush.CreateBrush("Blue102", 0x660000ff)
gw.FillEllipse(brush["Red255"], 100, 500, 200, 300)
gw.FillRectangle(brush["Blue102"], 250, 80, 300, 200)
gw.UpdateLayeredWindow(0, 0)
brush.DisposeAll(), gw.DisposeGDIObj()
return

if we wrapped the library in a class

class Gdip
{
	__New()
	{
		this.pToken := Gdip_Startup()
	}
	
	__Delete()
	{
		Gdip_Shutdown(this.pToken)
	}
	
	class GDIWin
	{
		CreateGDIObj(hwnd, w, h, SmoothingMode = 4, InterpolationMode = 7)
		{
			this.width := w, this.height := h, this.hwnd := hwnd
			this.hbm := CreateDIBSection(w, h)
			this.hdc := CreateCompatibleDC()
			this.obm := SelectObject(this.hdc, this.hbm)
			this.G := Gdip_GraphicsFromHDC(this.hdc)
			Gdip_SetSmoothingMode(this.G, SmoothingMode)
			Gdip_SetInterpolationMode(this.G, InterpolationMode)
		}
		
		FillEllipse(pBrush, x, y, w, h)
		{
			Gdip_FillEllipse(this.G, pBrush, x, y, w, h)
		}
		
		FillRectangle(pBrush, x, y, w, h)
		{
			Gdip_FillRectangle(this.G, pBrush, x, y, w, h)
		}
		
		UpdateLayeredWindow(x="", y="")
		{
			if (x = "" && y = "")
				UpdateLayeredWindow(this.hwnd, this.hdc)
			else
				UpdateLayeredWindow(this.hwnd, this.hdc, x, y, this.width, this.height)	
		}
		
		DisposeGDIObj()
		{
			SelectObject(this.hdc, this.obm), DeleteObject(this.hbm), DeleteDC(this.hdc)
			Gdip_DeleteGraphics(this.G)
		}
	}
	
	class Brush
	{
		Names := Object()

		CreateBrush(Name, ARGB)
		{
			this[Name] := Gdip_BrushCreateSolid(ARGB)
			this.Names.Insert(Name)
		}
		
		DisposeBrush(Name)
		{
			Gdip_DeleteBrush(this[Name])
		}
		
		DisposeAll()
		{
			for index, element in this.Names
			{
				Gdip_DeleteBrush(this[element])
			}
		}
	}
}

We now have the possibility of separate windows that have everything they need associated with them and also can have a brush dictionary (named array).

Uberi
  • Moderators
  • 1119 posts
  • Last active: May 02 2015 06:05 PM
  • Joined: 23 Aug 2010
I'm doing something similar to that here, but it's designed to have a subset of GDI+ features that can also be supported by other graphics APIs, like OpenGL.

Code that uses it looks something like this right now:

Posted Image

s := new Canvas.Surface(200,200)

Gui, +LastFound
v := new Canvas.Viewport(WinExist())
v.Attach(s)

p := new Canvas.Pen(0x80FF0000,10)
t := new Canvas.Pen(0xFF00FF00,3)
b := new Canvas.Brush(0xAA0000FF)

s.Clear(0xFFFFFF00)
 .Push()
 .Translate(50,50)
 .Rotate(60)
 .FillRectangle(b,0,0,50,50)
 .Pop()
 .DrawEllipse(p,70,70,100,100)
 .DrawCurve(t,[[10,10],[50,10],[10,50]],True)

Gui, Show, w200 h200, Canvas Demo
Return

GuiClose:
ExitApp

The main principle is, "do it with less boilerplate". It's a slightly thicker wrapper over GDI+, emulating things like a transform stack for easier transformations, automatically subclassing windows and controls to draw on them, and extensive error checking.

Leef_me
  • Moderators
  • 8510 posts
  • Last active: Sep 10 2015 05:50 AM
  • Joined: 08 Apr 2009

djvj

I have also demonstrated how you can avoid recreating a new bitmap each time by creating the bitmap initially to be the largest it will ever be.


Actually for any given rotation the largest dimension will be equal to the length of the diagonal. That is, sqrt(w**2+h**2).

For 90 degree increments, the largest dimension will be max(w,h).

An angle causing the maximum dimension to appear is w*atan(h/2).


I believe that angle would actually be --> atan(h/w)

Wicked
  • Members
  • 504 posts
  • Last active: Nov 02 2017 11:07 PM
  • Joined: 07 Jun 2008
Perhaps someone here can help with a rather simple problem.

I have a rectangular image. I want GDI+ to crap the image, but not in a square. I need it to:
Posted Image

What I was thinking:
- Obviously size the image appropriately.
- Create a second same-size bitmap and paint it entirely white (or another color).
- Change the compositing mode and remove a circular shape of the correct size.
- Paint the new bitmap onto the one of the actual image.
- Use:
Gdip_FilterColor(pBitmap,Color)
{
   Gdip_GetDimensions(pBitmap, w, h)
   pBitmap2 := Gdip_CreateBitmap(w, h)
   Gdip_LockBits(pBitmap, 0, 0, w, h, Stride1, Scan01, BitmapData1)
   Gdip_LockBits(pBitmap2, 0, 0, w, h, Stride2, Scan02, BitmapData2)
   Loop, %h%
   {
      y := A_Index-1
      Loop, %w%
      {
         x := A_Index-1
         ARGB := Gdip_GetLockBitPixel(Scan01, x, y, Stride1)
         if (ARGB = Color)
            Gdip_SetLockBitPixel(ARGB,Scan02,x, y,Stride2)
      }
   }
   Gdip_UnlockBits(pBitmap, BitmapData1), Gdip_UnlockBits(pBitmap2, BitmapData2)
   Gdip_DisposeImage(pBitmap)
   return pBitmap2
}
To filter out all of the pixels containing white (or whatever color we chose.

Is there any better method that I'm possibly overlooking?

3nL8f.png


Uberi
  • Moderators
  • 1119 posts
  • Last active: May 02 2015 06:05 PM
  • Joined: 23 Aug 2010

Is there any better method that I'm possibly overlooking?


Maybe you can construct a region the same size as the bitmap, subtract an ellipse from it, and paint it onto the bitmap with the desired background color? Here are a few links to get you started:

<!-- m -->http://msdn.microsof...y/4t53hf8d.aspx<!-- m -->
<!-- m -->http://msdn.microsof... ... 01(v=vs.85<!-- m -->).aspx

This should be quite a bit faster than the LockBits method.

guest3456
  • Members
  • 1704 posts
  • Last active: Nov 19 2015 11:58 AM
  • Joined: 10 Mar 2011

I modifed the Gdip.ahk file to support all 4 of the main AHK builds: Basic, _L ANSI, _L Unicode x86 and x64. Thanks to fincs for the AHK_L only version of the library that had 64 bit support.

Download >here<

I tested all of the example scripts on the first post and everything worked fine. This doesn't include any of the BRA functions.


great work by all

Wicked
  • Members
  • 504 posts
  • Last active: Nov 02 2017 11:07 PM
  • Joined: 07 Jun 2008
I don't know how I missed it, Uberi... But Gdip_SetClipPath() worked great. I was searching for regions, as you suggested, and found that tic had already included this useful function! Thanks!

3nL8f.png


tic
  • Members
  • 1934 posts
  • Last active: Dec 21 2015 01:05 PM
  • Joined: 22 Apr 2007

I don't know how I missed it, Uberi... But Gdip_SetClipPath() worked great. I was searching for regions, as you suggested, and found that tic had already included this useful function! Thanks!


Could I see the code you have created? Are you adding antialiasing to the created circle?

Wicked
  • Members
  • 504 posts
  • Last active: Nov 02 2017 11:07 PM
  • Joined: 07 Jun 2008
No, I had no need for antialiasing. I needed it to create quick templates which could be dragged into Photoshop. But, the circles I needed had to be at x18 y18 with a w and h of 180. So I used (not exact code, but you get the idea):
Gdip_AddPathEllipse(P:=Gdip_CreatePath(),18,18,180,180),Gdip_SetClipPath(G:=Gdip_GraphicsFromImage(B:=Gdip_CreateBitmap(216,216)),P)
Gdip_DrawImage(G,F:=Gdip_CreateBitmapFromFile("Example.png"),0,0,216,216)
Gdip_SaveBitmapToFile(B,"Example-Crop.png")
Gdip_DisposeImage(F),Gdip_DisposeImage(B),Gdip_DeleteGraphics(G)

I was also surprised that I could simply add more clip area by simply doing:
Gdip_AddPathEllipse(P,243,18,180,180)
Gdip_AddPathEllipse(P,18,243,180,180)
Gdip_AddPathEllipse(P,243,243,180,180)

For some reason, for a while, the Gdip_CreatePath() was returning a strange directory. So I changed the Path to pPath and it solved the issue.

Posted Image

Maybe a good idea for the tutorial?

3nL8f.png


tic
  • Members
  • 1934 posts
  • Last active: Dec 21 2015 01:05 PM
  • Joined: 22 Apr 2007
I never really liked regions or paths as they stop you using antialiasing for things like this. You could write a hack to create your own like below:

pToken := Gdip_Startup()
pBitmap := Gdip_CreateBitmapFromFile("MJ.jpg")

pBitmap2 := CircleCrop(pBitmap, 100, 50, 300, 300)
Gdip_SaveBitmapToFile(pBitmap2, "Circle.png")

Gdip_DisposeImage(pBitmap), Gdip_DisposeImage(pBitmap2)
Gdip_Shutdown(pToken)
return

CircleCrop(pBitmap, x, y, w, h)
{
	static _CircleCrop
	if !_CircleCrop
	{
		MCode_CircleCrop := "8B44241C9983E20303C28BC88B4424209983E20303C28B542418C1F902C1F80285D27E6803C003C0894424208D048D000000000"
		. "FAF4C2428034C2424535556894424288B442410578B7C24188BDA8B5424248D348885D27E228BC78BCE8D49008B29332883C10481E5FFFFFF00312883"
		. "C00483EA0175E98B5424240374242C037C243083EB0175CD5F5E5D5B33C0C3"

		VarSetCapacity(_CircleCrop, StrLen(MCode_CircleCrop)//2)
		Loop % StrLen(MCode_CircleCrop)//2      ;%
			NumPut("0x" SubStr(MCode_CircleCrop, (2*A_Index)-1, 2), _CircleCrop, A_Index-1, "char")
	}
	Gdip_GetDimensions(pBitmap, w1, h1)
	pBitmap2 := Gdip_CreateBitmap(w, h), G2 := Gdip_GraphicsFromImage(pBitmap2)
	Gdip_SetSmoothingMode(G2, 4)
	
	pBrush := Gdip_BrushCreateSolid(0xff00ff00)
	Gdip_FillEllipse(G2, pBrush, 0, 0, w, h)
	Gdip_DeleteBrush(pBrush)
	
	E1 := Gdip_LockBits(pBitmap, 0, 0, w1, h1, Stride1, Scan01, BitmapData1)
	E2 := Gdip_LockBits(pBitmap2, 0, 0, w, h, Stride2, Scan02, BitmapData2)
	
	E := DllCall(&_CircleCrop, "ptr", Scan01, "ptr", Scan02, "int", w1, "int", h1, "int", w, "int", h, "int", Stride1, "int", Stride2, "int", x, "int", y)
	
	Gdip_UnlockBits(pBitmap, BitmapData1), Gdip_UnlockBits(pBitmap2, BitmapData2)
	Gdip_DeleteGraphics(G2)
	return pBitmap2
}

Posted Image

int CircleCrop(unsigned int * Bitmap, unsigned int * BitmapCircle, int w1, int h1, int w2, int h2, int Stride1, int Stride2, int sx, int sy)
{
	int o1 = Stride1/4, o2 = Stride2/4;
	for (int y = 0; y < h2; ++y)
	{
		for (int x = 0; x < w2; ++x)
		{
			BitmapCircle[x+(y*o2)] = (BitmapCircle[x+(y*o2)] & 0xff000000) | (Bitmap[(x+sx)+(y+sy)*o1] & 0x00ffffff);
		}
	}
	return 0;
}

The function would probably need a better name and some error checking :wink:

Uberi
  • Moderators
  • 1119 posts
  • Last active: May 02 2015 06:05 PM
  • Joined: 23 Aug 2010
How about Gdip_AlphaMask()? You'd give it a source bitmap as input, and a mask bitmap that the function uses the value of to modulate the alpha channel of the output bitmap.

Useful for a ton of things other than just cropping - it would give the ability to easily modify alpha channels.

GdipAll
  • Guests
  • Last active:
  • Joined: --
http://www.autohotke...ll/Gdip_All.ahk
Good job, but Gdip_SaveBitmapToFile() does not work when you run the script with AutoHotkey_L 64-bit Unicode and try to extract icon from exe.
; Run the script with AutoHotkey_L 64-bit Unicode
FullPath := A_AhkPath
pToken := Gdip_Startup()
pBitmap := Gdip_CreateBitmapFromFile(FullPath)	; (FullPath,1,48) doesn't help
MsgBox % pBitmap								; returns -2 on 64-bit
Gdip_SaveBitmapToFile(pBitmap, A_ScriptDir "\Gdiptest.png")
Gdip_DisposeImage(pBitmap)
Gdip_Shutdown(pToken)
Run, % A_ScriptDir "\Gdiptest.png"
ExitApp

#Include Gdip_All.ahk