Rotate images with vfp9 gdiplus and gdiplusX classes

Published on by Yousfi Benameur


Native gdiplus.vcx shipped with vfp9 is few used by vfp developpers .its a minimalistic class and its not very documented and miss decorated by examples.I dont see VFP developments on the wordl wide web with this class !
gdiplusX translated from .net technology is more reliable and contains more than 600 APIS for drawing technics.
the native vfp9 gdiplus class have the advantage its already in vfp9 IDE (dont need to load it from external file).
image.rotateflip property does some known rotations/flips only for some specific angles:
	image.rotateFlip=nValue see in help constantscover  0-7 values.
this dont know how to rotate an image at a given angle.
 also vfp image control have not a rotation peoperty in its PEM.

for that purpose and in code *1*  need the object gpimage and the object gpGraphics of gdiplus class.
however this is an example demonstrating how rotate an image at any angle 0 to 360 degrees even animated rotations.

note that code use form with showWindow=0,1,2...see the relative handle hwnd in code.
gdiplus nor gdiplusX dont document how to work with form.showWindow=2 (top leve form).I already wrote a previous post on that.
it uses simply to values of form.HWND to achieve this goal

With   Thisform
.addproperty("RealHWND",.f.)
.realhwnd = Iif(.ShowWindow = 2, Sys(2327, Sys(2325, Sys(2326,.HWnd))), .HWnd)
Endwith

for more PEM on object gpImage and gpGraphics see in help these chapters:
GDI Plus Graphics Foundation Class
GDI Plus Bitmap Foundation Class


Click on code to select [then copy] -click outside to deselect


*1*  rotating an image with native vfp9 gdiplus class
*!*	for that purpose need the object gpimage and the object gpGraphics of gdiplus class.
*!*	however this is an example demonstrating how rotate an image at any angle 0 to 360 degrees.
*!*note that code use form with showWindow=0,1,2...see the relative handle hwnd in code.

*the code downloads first working image from my blog (or point later on the form to any image on disc)
Declare Integer Sleep In kernel32 Integer
Declare Integer URLDownloadToFile In urlmon.Dll Integer pCaller, String szURL, String szFileName, Integer dwReserved, Integer lpfnCB
Declare Integer DeleteUrlCacheEntry In wininet String lpszUrlName

lcDownloadURL = "http://img.over-blog-kiwi.com/1/43/54/07/20170119/ob_5995a2_ycolorwheel5png.png"
lcDownloadLoc ="ycolorwheel.png"
lnResult = DeleteUrlCacheEntry(lcDownloadURL)
lnResult = URLDownloadToFile(0, lcDownloadURL, lcDownloadLoc , 0,0)
If lnResult = 0
    Wait Window "Download "+lcDownloadLoc +"  Complete" Nowait
*Else
*!*  Messagebox("Download fails")
Endi


Publi yform
yform=Newobject("yrotations")
yform.Show
Read Events
Retu

Define Class yrotations As Form
	Top = -1
	Left = 17
	Height = 577
	Width = 962
	ShowWindow = 2
	ShowTips = .T.
	Caption = "Rotate image with vfp9 gdiplus class -  artistic effect"
	BackColor = Rgb(212,210,208)
	realhwnd = .F.
	Name = "Form1"

	Add Object image1 As Image With ;
		Picture = "ycolorwheel.png", ;
		Height = 300, ;
		Left = 336, ;
		Top = 240, ;
		Width = 300, ;
		Name = "Image1"

	Add Object container1 As ycnt With ;
		Anchor = 768, ;
		Top = 6, ;
		Left = 10, ;
		Width = 350, ;
		Height = 66, ;
		BackStyle = 0, ;
		BorderWidth = 0, ;
		BackColor = Rgb(0,0,0), ;
		Name = "Container1"


	Add Object shape1 As Shape With ;
		Top = 4, ;
		Left = 936, ;
		Height = 14, ;
		Width = 14, ;
		Anchor = 768, ;
		Curvature = 99, ;
		MousePointer = 15, ;
		ToolTipText = "Hide/show controls", ;
		BackColor = Rgb(255,0,0), ;
		Name = "Shape1"


	Procedure Init
		With   Thisform
			.realhwnd = Iif(.ShowWindow = 2, Sys(2327, Sys(2325, Sys(2326,.HWnd))), .HWnd)
		Endwith
		Thisform.WindowState=2
	Endproc

	Procedure Destroy
		Clea Events
	Endproc

	Procedure Resize
		With Thisform.image1
			.Left=(Thisform.Width-.Width)/2
			.Top=(Thisform.Height-.Height)/2
		Endwith
	Endproc

	Procedure shape1.Click
		With Thisform.container1
			.Visible=!.Visible
			If .Visible=.F.
				Set Curs Off
				Thisform.container1.command2.Click()  &&redraw
			Else
				Set Curs On
			Endi
		Endwith
	Endproc

Enddefine
*
*-- EndDefine: yrotations
Define Class ycnt As Container
	Anchor = 768
	Top = 6
	Left = 10
	Width = 350
	Height = 66
	BackStyle = 0
	BorderWidth = 0
	BackColor = Rgb(0,0,0)
	Name = "Container1"

	Add Object spinner1 As Spinner With ;
		Height = 24, ;
		Left = 39, ;
		SpecialEffect = 2, ;
		KeyboardHighValue = 360, ;
		KeyboardLowValue = 1, ;
		increment=2,;
		SpinnerHighValue = 360.00, ;
		SpinnerLowValue =   1.00, ;
		value=1,;
		ToolTipText = "Rotation 1°", ;
		Top = 5, ;
		Width = 78, ;
		Name = "Spinner1"

	Add Object check1 As Checkbox With ;
		Top = 6, ;
		Left = 122, ;
		Height = 17, ;
		Width = 42, ;
		AutoSize = .T., ;
		Alignment = 0, ;
		BackStyle = 0, ;
		Caption = "CLS", ;
		Name = "Check1"

	Add Object command2 As CommandButton With ;
		Top = 6, ;
		Left = 170, ;
		Height = 27, ;
		Width = 96, ;
		FontBold = .T., ;
		Caption = "Rotate 0-360°", ;
		MousePointer = 15, ;
		SpecialEffect = 2, ;
		BackColor = Rgb(128,255,0), ;
		Name = "Command2"

	Add Object command1 As CommandButton With ;
		Top = 2, ;
		Left = 0, ;
		Height = 27, ;
		Width = 38, ;
		FontBold = .T., ;
		Caption = "....", ;
		MousePointer = 15, ;
		ToolTipText = "Get a picture", ;
		BackColor = Rgb(255,255,0), ;
		Name = "Command1"

	Add Object text1 As TextBox With ;
		Alignment = 3, ;
		Value = 1.00, ;
		Height = 25, ;
		InputMask = "999.999", ;
		Left = 278, ;
		ToolTipText = "Scale X", ;
		Top = 2, ;
		Width = 60, ;
		Name = "Text1"

	Add Object text2 As TextBox With ;
		Alignment = 3, ;
		Value = 1.00, ;
		Height = 25, ;
		InputMask = "999.999", ;
		Left = 278, ;
		ToolTipText = "scaleY", ;
		Top = 29, ;
		Width = 60, ;
		Name = "Text2"

	Add Object command3 As CommandButton With ;
		AutoSize = .T., ;
		Top = 33, ;
		Left = 186, ;
		Height = 27, ;
		Width = 65, ;
		FontBold = .T., ;
		Caption = "Capture", ;
		MousePointer = 15, ;
		BackColor = Rgb(255,128,64), ;
		Name = "Command3"

	Add Object command4 As CommandButton With ;
		AutoSize = .T., ;
		Top = 34, ;
		Left = 4, ;
		Height = 27, ;
		Width = 43, ;
		FontBold = .T., ;
		Caption = "CLS", ;
		MousePointer = 15, ;
		BackColor = Rgb(128,0,255), ;
		Name = "Command4"

	Add Object spinner2 As Spinner With ;
		Comment = "30", ;
		Height = 24, ;
		KeyboardHighValue = 360, ;
		KeyboardLowValue = 1, ;
		Left = 55, ;
		SpinnerHighValue = 360.00, ;
		SpinnerLowValue =   1.00, ;
		ToolTipText = "nStep", ;
		Top = 37, ;
		Width = 91, ;
		Value = 10, ;
		Name = "Spinner2"

	Procedure spinner1.InteractiveChange
		Local loimage As gpimage Of ffc/_gdiplus.vcx
		loimage = Newobject("gpimage",Home()+"ffc/_gdiplus.vcx")
		loimage.createfromfile(Thisform.image1.Picture)
		Thisform.image1.Visible=.T.

		x0=Thisform.image1.Left+Thisform.image1.Width/2
		y0=Thisform.image1.Top+Thisform.image1.Height/2

		gfx=Newobject("gpGraphics",Home()+"ffc/_gdiplus.vcx")
		gfx.createfromhwnd(Thisform.realhwnd)   && form.showWindow=0,1 ,t 2

		If This.Parent.check1.Value=1
			Thisform.Cls
		Endi
		* rotate the gfx
		gfx.translatetransform(x0, y0)
		gfx.rotatetransform(This.Value)
		gfx.translatetransform(- x0, - y0)
		gfx.ScaleTransform(This.Parent.text1.Value, This.Parent.text2.Value)
		* draw image
		gfx.drawImageAt(loimage,x0,y0)
		* restore the original gfx rotation state
		gfx.resettransform()

		gfx=Null
		loimage=Null
	Endproc

	Procedure command2.Click
		Local loimage As gpimage Of ffc/_gdiplus.vcx
		loimage = Newobject("gpimage",Home()+"ffc/_gdiplus.vcx")
		loimage.createfromfile(Thisform.image1.Picture)

		x0=Thisform.image1.Left+Thisform.image1.Width/2
		y0=Thisform.image1.Top+Thisform.image1.Height/2

		Thisform.ForeColor=255
		Thisform.Line(x0,0,x0,2*y0)
		Thisform.Line(0,y0,2*x0,y0)

		gfx=Newobject("gpGraphics",Home()+"ffc/_gdiplus.vcx")
		gfx.createfromhwnd(Thisform.realhwnd)   && form.showWindow=0,1 ,t 2

		Local nstep
		nstep=Thisform.container1.spinner2.Value
		For i=0 To 360 Step nstep
			If This.Parent.check1.Value=1
				Thisform.Cls
			Endi
			*rotate the gfx
			gfx.translatetransform(x0, y0)
			gfx.rotatetransform(i)
			gfx.translatetransform(- x0, - y0)
			gfx.ScaleTransform(This.Parent.text1.Value, This.Parent.text2.Value)
			*draw image
			gfx.drawImageAt(loimage,x0,y0)
			*restore the original gfx rotation state
			gfx.resettransform()
			Inke(0.1)
		Endfor

		gfx=Null
		loimage=Null
	Endproc

	Procedure command1.Click
		Local m.xpict
		m.xpict=Getpict()
		If !Empty(m.xpict)
			Thisform.image1.Picture=m.xpict
		Endi
	Endproc

	Procedure command3.Click
		Try
			Run/N snippingtool.Exe
		Catch
			Messagebox("Snippingtool not installed !",16+4096)
		Endtry
	Endproc

	Procedure command4.Click
		Thisform.Cls
	Endproc


Enddefine
*
*-- EndDefine:ycnt


variying nstep in spinner2 can obtain various artistic rendered images.
variying nstep in spinner2 can obtain various artistic rendered images.
variying nstep in spinner2 can obtain various artistic rendered images.
variying nstep in spinner2 can obtain various artistic rendered images.
variying nstep in spinner2 can obtain various artistic rendered images.
variying nstep in spinner2 can obtain various artistic rendered images.
variying nstep in spinner2 can obtain various artistic rendered images.
variying nstep in spinner2 can obtain various artistic rendered images.
variying nstep in spinner2 can obtain various artistic rendered images.
variying nstep in spinner2 can obtain various artistic rendered images.
variying nstep in spinner2 can obtain various artistic rendered images.
variying nstep in spinner2 can obtain various artistic rendered images.
variying nstep in spinner2 can obtain various artistic rendered images.
variying nstep in spinner2 can obtain various artistic rendered images.
variying nstep in spinner2 can obtain various artistic rendered images.
variying nstep in spinner2 can obtain various artistic rendered images.

variying nstep in spinner2 can obtain various artistic rendered images.

Click on code to select [then copy] -click outside to deselect

*2* using gdiplusX class to rotate an image
*modifying nstep can give many results.
*can transpose the form of code *1* here for visual demo to user. 
*here drawing is not cleared to leave some image effects by rotation.

LOCAL lcSource, lnWidth, lnHeight
lcSource = GETPICT()
IF EMPTY(lcSource)
   RETURN
ENDIF
DO LOCFILE("System.App")
set defa to addbs(justpath(sys(16,1)))

WITH _SCREEN.System.Drawing
LOCAL loBmp0,loBMP AS xfcBitmap
loBMP0=.bitmap.new(_screen.width,_screen.height)
logfx= .Graphics.FromImage(loBmp0)
logfx.clear(.color.white)

xc=_screen.width/2
yc=_screen.height/2

loBmp = .Bitmap.FromFile(lcSource)
w=loBMP.width/2
h=loBMP.height/2
local nstep
nstep=10    &&can modify for difrent results

oState = loGfx.Save()
loGfx.TranslateTransform(xc,yc)
for i=0 to 360 step nstep
loGfx.RotateTransform(i)
loGfx.DrawImage(loBmp,0,0,w,h)
endfor
PEN = .PEN.NEW(.color.red, 4)
loGfx.DrawEllipse(pen,0,0,5,5)
loGfx.restore(oState)
local m.lcdest
m.lcdest="miror.png"

loBmp0.Save(m.lcdest, .Imaging.ImageFormat.Png)
RUN /N "mspaint" &lcdest
 endwith
 retu




varying nstep in loop produces difrent results.
varying nstep in loop produces difrent results.
varying nstep in loop produces difrent results.
varying nstep in loop produces difrent results.

varying nstep in loop produces difrent results.

this image is used in code *1* as demo.

this image is used in code *1* as demo.

Rotate images with vfp9 gdiplus and gdiplusX classes

Important:All Codes above are tested on VFP9SP2 & windows 10 pro

To be informed of the latest articles, subscribe:
Comment on this post