Page 14 of 22

Re: GDI+ standard library 1.45 by tic

Posted: 18 Dec 2018, 09:05
by _Ne0n
nnnik, thank u for hint. I saw on this function, but not used it cos it draw's bitmap into pGraphics. (I needed DC>DC) I will try do something with it.

Re: GDI+ standard library 1.45 by tic

Posted: 27 Dec 2018, 18:51
by _Ne0n
How it looks? :0
Just AHK and GDI+.

Re: GDI+ standard library 1.45 by tic

Posted: 27 Dec 2018, 20:44
by nnnik
Nice gj

Re: GDI+ standard library 1.45 by tic

Posted: 08 Jan 2019, 12:45
by _Ne0n
Hello :)
I have next function:
Spoiler
If in addition to the file directory, put a the height and width, then function reduce/enlarge the image, while maintaining the proportions.
MsgBox at the same time displays about 265ms, which is not good.
Someone faced with this?
I convert image 4160x2340 to 72x72.

Re: GDI+ standard library 1.45 by tic

Posted: 12 Mar 2019, 02:31
by jeeswg
- Hello, to support #Warn, changes like this need to be done for IntP/UIntP/PtrP etc in DllCall. I.e. you assign a value in advance.

Code: Select all

	;Warning:  This variable has not been assigned a value.
	;before:
	DllCall("Ole32.dll\CreateStreamOnHGlobal", "Ptr", hData, "Int", 1, "PtrP", pStream)

	;after:
	pStream := 0
	DllCall("Ole32.dll\CreateStreamOnHGlobal", "Ptr", hData, "Int", 1, "PtrP", pStream)

	;after (alternative):
	DllCall("Ole32.dll\CreateStreamOnHGlobal", "Ptr", hData, "Int", 1, "PtrP", pStream:=0)
- Also, to support #Warm, 'local' by itself should be added to every function.
- Although, this would mean that you'd need AHK v1.1.27+ to use the library.
- That said, the users could remove 'local', to make it work on older versions. Thanks.

Re: GDI+ standard library 1.45 by tic

Posted: 21 Mar 2019, 21:41
by iseahound
What is the purpose of lines such as

Code: Select all

	pBitmap := ""

inside

Code: Select all

Gdip_CreateBitmapFromHICON(hIcon)
{
	pBitmap := ""

	DllCall("gdiplus\GdipCreateBitmapFromHICON", A_PtrSize ? "UPtr" : "UInt", hIcon, A_PtrSize ? "UPtr*" : "uint*", pBitmap)
	return pBitmap
}
They actually don't do anything.

Re: GDI+ standard library 1.45 by tic

Posted: 22 Mar 2019, 01:44
by swagfag
so it doesn't upset #warn methinks

Re: GDI+ standard library 1.45 by tic

Posted: 22 Mar 2019, 08:51
by guest3456
yes if you guys are talking about the v1/v2 version of the lib

one guy already added support for #WarnAll

example commit
https://github.com/mmikeww/AHKv2-Gdip/commit/8f7a787c94f3339ecc27c20a2e71c77426210be4

Re: GDI+ standard library 1.45 by tic

Posted: 22 Mar 2019, 10:55
by iseahound
For the DllCall standardization, are we doing lowercase or uppercase letters?

Code: Select all

DllCall( "SendMessage", Ptr, hwnd, "UInt", 0x172, "UInt", 0x0, Ptr, hBitmap )
to

Code: Select all

DllCall( "SendMessage", "Ptr", hwnd, "UInt", 0x172, "UInt", 0x0, "Ptr", hBitmap )
or

Code: Select all

DllCall( "SendMessage", "ptr", hwnd, "uint", 0x172, "uint", 0x0, "ptr", hBitmap )
I feel like it shouldn't really matter, other than size arguments are encased in quotes for maximum compatibility, speed, and reliability.

Re: GDI+ standard library 1.45 by tic

Posted: 22 Mar 2019, 11:54
by iseahound
I realized why the #Warn changes bothered me. If the variable is initalized, then the address should be passed.

Code: Select all

Gdip_CreateBitmapFromHICON(hIcon)
{
	pBitmap := ""

	DllCall("gdiplus\GdipCreateBitmapFromHICON", A_PtrSize ? "UPtr" : "UInt", hIcon, A_PtrSize ? "UPtr*" : "uint*", pBitmap)
	return pBitmap
}
becomes

Code: Select all

Gdip_CreateBitmapFromHICON(hIcon)
{
	pBitmap := ""

	DllCall("gdiplus\GdipCreateBitmapFromHICON", A_PtrSize ? "UPtr" : "UInt", hIcon, A_PtrSize ? "UPtr" : "uint", &pBitmap)
	return pBitmap
}
I changed uint* to plain old uint since we already have the address via &pBitmap.

Re: GDI+ standard library 1.45 by tic

Posted: 22 Mar 2019, 17:02
by swagfag
iseahound wrote:
22 Mar 2019, 11:54
If the variable is initalized, then the address should be passed.
why? it works either way. yes u can use "Ptr" and &, but what practical difference does it make

Re: GDI+ standard library 1.45 by tic

Posted: 23 Mar 2019, 00:50
by Helgef
Don't do that iseahound, that is undefined behaviour. You need to use varsetcapacity and numget if you use ptr vs ptr*.

Edit, in v2 you can do "ptr", &var := 0.

Re: GDI+ standard library 1.45 by tic

Posted: 24 Mar 2019, 10:35
by iseahound
Helgef wrote:
23 Mar 2019, 00:50
Edit, in v2 you can do "ptr", &var := 0.
Not that I would, but do I interpret that as "ptr", &(var := 0)?

Re: GDI+ standard library 1.45 by tic

Posted: 24 Mar 2019, 14:13
by Helgef
yes.
Operators in Expressions wrote:The precedence of the assignment operators is automatically raised when it would avoid a syntax error or provide more intuitive behavior.

Re: GDI+ standard library 1.45 by tic

Posted: 26 Mar 2019, 15:12
by jeeswg
- @iseahound: The reason is to avoid #Warn errors, e.g. 'Warning: This variable has not been assigned a value.'
- There is an advantage also that such code is easier to translate to other languages.
- I've updated my example earlier on this page, to demonstrate that you can do var:=0 within the DllCall function call, a 3-character fix to avoid the warning: :=0.

Re: GDI+ standard library 1.45 by tic

Posted: 12 Apr 2019, 01:20
by RazorHalo
Hi All,

I was wondering if using DllCall can we only access the Functions of GDI+ or is there also a way to use it's methods.
I want to rotate a graphicspath on the center of its bounding rectangle and it would be a lot easier if I could use the RotateAt method.

It looks to me like I can only access the functions in the dll, any attempt to use the RotateAt method yields no returned status code at all.

Function:
https://docs.microsoft.com/en-us/windows/desktop/gdiplus/-gdiplus-matrix-flat

Method:
https://docs.microsoft.com/en-us/windows/desktop/api/gdiplusmatrix/nf-gdiplusmatrix-matrix-rotateat

Maybe there is a way to access it that I'm not aware of? I can't seem to find any reference to this from searching.

RH

Re: GDI+ standard library 1.45 by tic

Posted: 12 Apr 2019, 02:21
by swagfag
no there isn't. only functions

Re: GDI+ standard library 1.45 by tic

Posted: 12 Apr 2019, 07:50
by nnnik
The RotateAt method is a C++ library wrapper around the DllCalls.
This specific method probably just performs multiple of the basic operations:
  • Move the point that you want to rotate around to the center using GdipTranslateMatrix
  • Rotate using GdipRotateMatrix
  • Move the point back to where it was before
In AHK we can't access the C++ wrapper library but need to write our own.

Re: GDI+ standard library 1.45 by tic

Posted: 12 Apr 2019, 23:51
by guest3456
the Matrix::RotateAt link mentions "gdiplusmatrix.h" as a requirement. googling the source for that file i found a few diff options, this one looked closest to what you'd need to do:

https://pdfium.googlesource.com/pdfium/+/5110c4743751145c4ae1934cd1d83bc6c55bb43f/core/src/fxge/Microsoft%20SDK/include/GdiPlusMatrix.h

Code: Select all

    Status RotateAt(IN REAL angle, 
                    IN const PointF& center, 
                    IN MatrixOrder order = MatrixOrderPrepend)
    {
        if(order == MatrixOrderPrepend)
        {
            SetStatus(DllExports::GdipTranslateMatrix(nativeMatrix, center.X, center.Y, order));
            SetStatus(DllExports::GdipRotateMatrix(nativeMatrix, angle, order));
            return SetStatus(DllExports::GdipTranslateMatrix(nativeMatrix, - center.X, - center.Y, order));
        }
        else
        {
            SetStatus(DllExports::GdipTranslateMatrix(nativeMatrix, - center.X, - center.Y, order));
            SetStatus(DllExports::GdipRotateMatrix(nativeMatrix, angle, order));
            return SetStatus(DllExports::GdipTranslateMatrix(nativeMatrix, center.X, center.Y, order));
        }
    }

Re: GDI+ standard library 1.45 by tic

Posted: 13 Apr 2019, 00:15
by RazorHalo
Thanks guys, after playing around for a few hours I was able to get it working. Here are the GDip Matrix functions I wrapped for the rotations and a sample script to see it implemented.

The thing that got me stuck the most was not realizing the order the transformations were applied with the MatrixOrder variable. It needs to be Append for this so that it will always put the transformation you want to do AFTER the one you just did. I'm sure there is a reason that it is defaulted to Prepend, but it doesn't make sense to me to do it in that order.

Matrix Functions for Gdip
Just add them to your GDip_All.ahk for future use:

Code: Select all

;#####################################################################################
; Matrix functions added by RazorHalo
;#####################################################################################

; NOTE: Be aware of the order that transoformations are applied.  You may need to pass MatrixOrder as 1 for "Append"
; the (default is 0 for "Prepend") to get the correct results.

Gdip_ResetMatrix(pMatrix)
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"

   return DllCall("gdiplus\GdipResetMatrix", Ptr, pMatrix)
}

Gdip_RotateMatrix(pMatrix, Angle, MatrixOrder=0)
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"

   return DllCall("gdiplus\GdipRotateMatrix", Ptr, pMatrix, "float", Angle, "Int", MatrixOrder)
}

Gdip_GetPathWorldBounds(pPath)
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"
	rData := {}

	VarSetCapacity(RectF, 16)
	NumPut(0, RectF, 0, "float"), NumPut(0, RectF, 4, "float"), NumPut(0, RectF, 8, "float"), NumPut(0, RectF, 12, "float")

	status := DllCall("gdiplus\GdipGetPathWorldBounds", Ptr, pPath, Ptr, &RectF)

	If (!status) {
			  rData.x := NumGet(RectF, 0, "float")
			, rData.y := NumGet(RectF, 4, "float")
			, rData.w := NumGet(RectF, 8, "float")
			, rData.h := NumGet(RectF, 12, "float")
	} Else {
		Return status
	}
	
   return rData
}

Gdip_ScaleMatrix(pMatrix, scaleX, scaleY, MatrixOrder=0)
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"

   return DllCall("gdiplus\GdipScaleMatrix", Ptr, pMatrix, "float", scaleX, "float", scaleY, "Int", MatrixOrder)
}

Gdip_TranslateMatrix(pMatrix, offsetX, offsetY, MatrixOrder=0)
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"

   return DllCall("gdiplus\GdipTranslateMatrix", Ptr, pMatrix, "float", offsetX, "float", offsetY, "Int", MatrixOrder)
}

Gdip_TransformPath(pPath, pMatrix)
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"

	return DllCall("gdiplus\GdipTransformPath", Ptr, pPath, Ptr, pMatrix)
}

Gdip_SetMatrixElements(pMatrix, m11, m12, m21, m22, x, y)
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"
	return DllCall("gdiplus\GdipSetMatrixElements", Ptr, pMatrix, "float", m11, "float", m12, "float", m21, "float", m22, "float", x, "float", y)
   
}
Gdip_GetLastStatus(pMatrix)
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"

	return DllCall("gdiplus\GdipGetLastStatus", Ptr, pMatrix)
}

Sample Script that will rotate a square around
Note - it uses the matrix functions I wrapped and needs some of the GraphicsPath Functions by Learning One

Code: Select all

#NoEnv
#SingleInstance Force
SetWorkingDir %A_ScriptDir%
SetBatchLines -1

;Need to include your path to Gdip or have in the same directory as script
#Include Gdip_all.ahk

Gui Mapper: New, hWndhMap -DPIScale +OwnDialogs
Gui Show, NA w600 h600, Mapper

Gui 1: +E0x80000 +LastFound -Caption -DPIScale +ParentMapper
hGui := WinExist()
Gui 1: Show, NA
w:= A_ScreenWidth, h:= A_ScreenHeight

pToken := Gdip_Startup()
hbm := CreateDIBSection(w, h), hdc := CreateCompatibleDC(), obm := SelectObject(hdc, hbm)
G := Gdip_GraphicsFromHDC(hdc), Gdip_SetSmoothingMode(G, 4)

;Create a GraphicsPath
pPath := Gdip_CreatePath() ; creates a Path (GraphicsPath object)

;Add figure to path
Gdip_StartPathFigure(pPath) ; starts a new figure in this Path
Gdip_AddPathLine(pPath, 200, 200, 400, 200)
Gdip_AddPathLine(pPath, 400, 200, 400, 400)
Gdip_AddPathLine(pPath, 400, 400, 200, 400)
Gdip_AddPathLine(pPath, 200, 400, 200, 200)
Gdip_ClosePathFigure(pPath) ; closes the current figure of this path

;Create a Pen to draw with
pPen := Gdip_CreatePen(0xff000000, 3)

;Rotate the graphic until exit
Loop {
	Gdip_GraphicsClear(G)						; Clear the graphics
	RotateAtCenter(pPath, 5)					; Rotate the path by 5deg on its center
	Gdip_DrawPath(G, pPen, pPath)				; draw rectangle
	UpdateLayeredWindow(hGui, hdc, 0, 0, w, h)	; Update the layred window
	Sleep 100
}

Esc::
;Cleanup and Exit
Gdip_DeletePen(pPen)
SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc)
Gdip_DeleteGraphics(G)
Gdip_Shutdown(pToken)
return
ExitApp

;#####################################################################################
; RotateAtCenter Function by RazorHalo
;#####################################################################################
;The Matrix order has to be "Append" for the transformations to be applied in the correct order - instead of the default "Prepend"

RotateAtCenter(pPath, Angle, MatrixOrder=1) {

	;Get bouinding rectangle of the graphics path
	;returns array x,y,w,h
	Rect := Gdip_GetPathWorldBounds(pPath)
	
	;Calcualte center of bounding rectangle which will be the center of the graphics path
	cX := Rect.x + (Rect.w / 2)
	cY := Rect.y + (Rect.h / 2)
	
	;Create a Matrix for the transformations
	pMatrix := Gdip_CreateMatrix()
	
	;Move the GraphicsPath center to the origin (0, 0) of the graphics object
	Gdip_TranslateMatrix(pMatrix, -cX , -cY)

	;Rotate matrix on graphics object origin
	Gdip_RotateMatrix(pMatrix, Angle, MatrixOrder)
	
	;Move the GraphicsPath origin point back to its original position
	Gdip_TranslateMatrix(pMatrix, cX, cY, MatrixOrder)

	;Apply the transformations
	Gdip_TransformPath(pPath, pMatrix)
	
	;Reset Matrix?  Delete Matrix?  Do I still need it for future rotations?
	GDip_DeleteMatrix(pMatrix)

}


;#####################################################################################
; GraphicsPath functions added by RazorHalo
;#####################################################################################

; NOTE: Be aware of the order that transoformations are applied.  You may need to pass MatrixOrder as 1 for "Append"
; the (default is 0 for "Prepend") to get the correct results.

Gdip_ResetMatrix(pMatrix)
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"

   return DllCall("gdiplus\GdipResetMatrix", Ptr, pMatrix)
}

Gdip_RotateMatrix(pMatrix, Angle, MatrixOrder=0)
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"

   return DllCall("gdiplus\GdipRotateMatrix", Ptr, pMatrix, "float", Angle, "Int", MatrixOrder)
}

Gdip_GetPathWorldBounds(pPath)
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"
	rData := {}

	VarSetCapacity(RectF, 16)
	NumPut(0, RectF, 0, "float"), NumPut(0, RectF, 4, "float"), NumPut(0, RectF, 8, "float"), NumPut(0, RectF, 12, "float")

	status := DllCall("gdiplus\GdipGetPathWorldBounds", Ptr, pPath, Ptr, &RectF)

	If (!status) {
			  rData.x := NumGet(RectF, 0, "float")
			, rData.y := NumGet(RectF, 4, "float")
			, rData.w := NumGet(RectF, 8, "float")
			, rData.h := NumGet(RectF, 12, "float")
	} Else {
		Return status
	}
	
   return rData
}

Gdip_ScaleMatrix(pMatrix, scaleX, scaleY, MatrixOrder=0)
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"

   return DllCall("gdiplus\GdipScaleMatrix", Ptr, pMatrix, "float", scaleX, "float", scaleY, "Int", MatrixOrder)
}

Gdip_TranslateMatrix(pMatrix, offsetX, offsetY, MatrixOrder=0)
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"

   return DllCall("gdiplus\GdipTranslateMatrix", Ptr, pMatrix, "float", offsetX, "float", offsetY, "Int", MatrixOrder)
}

Gdip_TransformPath(pPath, pMatrix)
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"

	return DllCall("gdiplus\GdipTransformPath", Ptr, pPath, Ptr, pMatrix)
}

Gdip_SetMatrixElements(pMatrix, m11, m12, m21, m22, x, y)
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"
	return DllCall("gdiplus\GdipSetMatrixElements", Ptr, pMatrix, "float", m11, "float", m12, "float", m21, "float", m22, "float", x, "float", y)
   
}
Gdip_GetLastStatus(pMatrix)
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"

	return DllCall("gdiplus\GdipGetLastStatus", Ptr, pMatrix)
}


;#####################################################################################
; GraphicsPath functions added by Learning one
;#####################################################################################

; Function Gdip_AddPathBeziers
; Description Adds a sequence of connected Bézier splines to the current figure of this path.
;
; pPath Pointer to the GraphicsPath
; Points the coordinates of all the points passed as x1,y1|x2,y2|x3,y3.....
;
; return status enumeration. 0 = success

; Notes The first spline is constructed from the first point through the fourth point in the array and uses the second and third points as control points. Each subsequent spline in the sequence needs exactly three more points: the ending point of the previous spline is used as the starting point, the next two points in the sequence are control points, and the third point is the ending point.

Gdip_AddPathBeziers(pPath, Points) {
StringSplit, Points, Points, |
VarSetCapacity(PointF, 8*Points0)
Loop, %Points0%
{
StringSplit, Coord, Points%A_Index%, `,
NumPut(Coord1, PointF, 8*(A_Index-1), "float"), NumPut(Coord2, PointF, (8*(A_Index-1))+4, "float")
}
return DllCall("gdiplus\GdipAddPathBeziers", "uint", pPath, "uint", &PointF, "int", Points0)
}

Gdip_AddPathBezier(pPath, x1, y1, x2, y2, x3, y3, x4, y4) { ; Adds a Bézier spline to the current figure of this path
return DllCall("gdiplus\GdipAddPathBezier", "uint", pPath
, "float", x1, "float", y1, "float", x2, "float", y2
, "float", x3, "float", y3, "float", x4, "float", y4)
}

; Function Gdip_AddPathLines
; Description Adds a sequence of connected lines to the current figure of this path.
;
; pPath Pointer to the GraphicsPath
; Points the coordinates of all the points passed as x1,y1|x2,y2|x3,y3.....
;
; return status enumeration. 0 = success

Gdip_AddPathLines(pPath, Points) {
StringSplit, Points, Points, |
VarSetCapacity(PointF, 8*Points0)
Loop, %Points0%
{
StringSplit, Coord, Points%A_Index%, `,
NumPut(Coord1, PointF, 8*(A_Index-1), "float"), NumPut(Coord2, PointF, (8*(A_Index-1))+4, "float")
}
return DllCall("gdiplus\GdipAddPathLine2", "uint", pPath, "uint", &PointF, "int", Points0)
}

Gdip_AddPathLine(pPath, x1, y1, x2, y2) {
return DllCall("gdiplus\GdipAddPathLine", "uint", pPath
, "float", x1, "float", y1, "float", x2, "float", y2)
}

Gdip_AddPathArc(pPath, x, y, w, h, StartAngle, SweepAngle) {
return DllCall("gdiplus\GdipAddPathArc", "uint", pPath, "float", x, "float", y, "float", w, "float", h, "float", StartAngle, "float", SweepAngle)
}

Gdip_AddPathPie(pPath, x, y, w, h, StartAngle, SweepAngle) {
return DllCall("gdiplus\GdipAddPathPie", "uint", pPath, "float", x, "float", y, "float", w, "float", h, "float", StartAngle, "float", SweepAngle)
}

Gdip_StartPathFigure(pPath) { ; Starts a new figure without closing the current figure. Subsequent points added to this path are added to the new figure.
return DllCall("gdiplus\GdipStartPathFigure", "uint", pPath)
}

Gdip_ClosePathFigure(pPath) { ; Closes the current figure of this path.
return DllCall("gdiplus\GdipClosePathFigure", "uint", pPath)
}

; Function Gdip_DrawPath
; Description draws a sequence of lines and curves defined by a GraphicsPath object
;
; pGraphics Pointer to the Graphics of a bitmap
; pPen Pointer to a pen
; pPath Pointer to a Path
;
; return status enumeration. 0 = success

Gdip_DrawPath(pGraphics, pPen, pPath) {
return DllCall("gdiplus\GdipDrawPath", "uint", pGraphics, "uint", pPen, "uint", pPath)
}

Gdip_WidenPath(pPath, pPen, Matrix=0, Flatness=1) { ; Replaces this path with curves that enclose the area that is filled when this path is drawn by a specified pen. This method also flattens the path.
return DllCall("gdiplus\GdipWidenPath", "uint", pPath, "uint", pPen, "uint", Matrix, "float", Flatness)
}

Gdip_ClonePath(pPath) {
DllCall("gdiplus\GdipClonePath", "uint", pPath, "uint*", pPathClone)
return pPathClone
}