Gdi+ provides many ways to draw rotated objects, like images, strings and shapes. Basically, we need to do a translate transformation to the location of the text, then a rotate transform through the required angle, and then writing the text as normal using drawstring.
This is the definition found in MSDN: "The rotation operation consists of multiplying the transformation matrix by a matrix whose elements are derived from the angle parameter. This method applies the rotation by prepending it to the transformation matrix."

IMPORTANT:
All samples below use the new GDIPlus-X library, that is still in ALPHA version, but is already stable and reliable to do the majority of GDI+ tasks. Download the latest stable release from Codeplex:
http://www.codeplex.com/Wiki/View.aspx?ProjectName=VFPX&title=GDIPlusX
* Initialize GdiPlus-X library
DO LOCFILE("System.App")
WITH _SCREEN.SYSTEM.Drawing
* Create a new and empty Bitmap
LOCAL loBmp as xfcBitmap
loBmp = .Bitmap.New(180,180)
* Create a Graphics object associated to the bitmap
LOCAL loGfx as xfcGraphics
loGfx = .Graphics.FromImage(loBmp)
* Clear the BackGround of the image with light blue
loGfx.Clear(.Color.FromRgb(230,230,255))
* Create a SolidBrush with Red Color
LOCAL loBrush AS xfcBrush
loBrush = .SolidBrush.New(.COLOR.FromRgb(255,0,0))
* The above statement could be also :
* loBrush = .SolidBrush.New(.COLOR.FromARgb(255,255,0,0))
* loBrush = .SolidBrush.New(.COLOR.Red)
* Create a Rectangle in which the rotated text will be drawn
LOCAL loRect AS xfcRectangle
loRect = .Rectangle.New(0, 0, loBmp.Width, loBmp.Height)
* Get a basic string format object, then set properties
LOCAL loStringFormat AS xfcStringFormat
loStringFormat = .StringFormat.New()
loStringFormat.ALIGNMENT = .StringAlignment.CENTER
loStringFormat.LineAlignment = .StringAlignment.CENTER
* Create a Font object
LOCAL loFont AS xfcFont
loFont = .FONT.New("Verdana",16, .FontStyle.Bold, .GraphicsUnit.POINT)
* After creating all needed objects, we can apply the rotation
* and draw the text
* Translate and Rotate
loGfx.TranslateTransform(loBmp.Width /2, loBmp.Height /2)
loGfx.RotateTransform(-45) && angle of 45 degrees
loGfx.TranslateTransform(-loBmp.Width /2, -loBmp.Height /2)
* Finally, draw the string
loGfx.DrawString("Rotated Text" + CHR(13) + CHR(10) + "GDIPlus-X is COOL !!!", ;
loFont, loBrush, loRect, loStringFormat)
* Reset Rotation
loGfx.ResetTransform()
* Save image to File
loBmp.Save("c:\rotated.png", .Imaging.ImageFormat.Png)
ENDWITH
* Show created image
RUN /N explorer.exe c:\rotated.png
TIME TO PLAY
For the above sample I used a cool trick to rotate the text at the center of the image, and not at the left edge, that is the default behavior. Now it's up to you to make some tests. Try omitting the two lines that call the Graphics.TranslateTransform, change the angle, using negative and positive angles, etc...
* Translate and Rotate
loGfx.TranslateTransform(loBmp.Width /2, loBmp.Height /2)
loGfx.RotateTransform(-45) && angle of 45 degrees
loGfx.TranslateTransform(-loBmp.Width /2, -loBmp.Height /2)
In the "Samples" folder of the latest GDIPlus-X library version there's another cool sample, "Rotation.Scx", in which another translation technique was used. All the codes are in the "BeforeDraw" method of the ImageCanvas object.
DRAW ROTATED STRINGS IN YOUR REPORTS !

The real reason for this post was a request from my friend from Foxbrasil Emerson Santon Reed, when he asked about creating a watermark of a big text rotated in 45 degrees in a report.
So, my part was just to adapt the GDI+ code shown above to the ReportListener class and Report that he provided.
Run the code below to see a rotated text centered at 45 degrees in a report:
* Create a sample Report
LOCAL i
CREATE CURSOR dummy (fld1 c(20), fld2 c(15))
FOR i=1 TO 100
INSERT INTO dummy VALUES ("ReportListener with GdiPlus-X", "Visit CodePlex")
ENDFOR
SELECT dummy
CREATE REPORT _testreport FROM dummy
* Init GdiPlus-X
DO LOCFILE("System.App")
* Load Listener class
LOCAL loreportlistener
loreportlistener = CREATEOBJECT("MyReportListener")
loreportlistener.LISTENERTYPE = 1
* Call the report using our listener
REPORT FORM _testreport OBJECT loreportlistener
USE IN dummy
RETURN
DEFINE CLASS myreportlistener AS _reportlistener OF ;
ADDBS(HOME()) + "FFC\" + "_ReportListener.VCX"
newPage = .T.
oGdigraphics = NULL
FUNCTION BEFOREREPORT
DODEFAULT()
This.ogdigraphics = _SCREEN.SYSTEM.drawing.graphics.new()
ENDFUNC
FUNCTION BEFOREBAND(nbandobjcode, nfrxrecno)
#DEFINE FRX_OBJCOD_PAGEHEADER 1
IF nbandobjcode==frx_objcod_pageheader
This.NewPage = .T.
IF NOT This.issuccessor
This.sharedgdiplusgraphics = This.GDIPLUSGRAPHICS
ENDIF
This.ogdigraphics.handle = This.sharedgdiplusgraphics
ENDIF
DODEFAULT(nBandObjCode, nFRXRecNo)
ENDFUNC
PROCEDURE RENDER(nfrxrecno,;
nleft,ntop,nwidth,nheight,;
nobjectcontinuationtype, ;
ccontentstoberendered, gdiplusimage)
WITH _SCREEN.SYSTEM.drawing
IF This.NewPage
* Create a SolidBrush with Red Color
LOCAL lobrush AS xfcbrush
lobrush = .solidbrush.new(.COLOR.fromRgb(255,64,64))
* Create a Rectangle in which the rotated text will be drawn
LOCAL lorect AS xfcrectangle
lorect = .rectangle.new(0, 0, This.sharedpagewidth,;
This.sharedpageheight)
* Get a basic string format object, then set properties
LOCAL lostringformat AS xfcstringformat
lostringformat = .stringformat.new()
lostringformat.ALIGNMENT = .stringalignment.CENTER
lostringformat.linealignment = .stringalignment.CENTER
* Create a Font object
LOCAL lofont AS xfcfont
lofont = .FONT.new("Verdana",48, 0, .graphicsunit.POINT)
* Translate and Rotate
This.ogdigraphics.translatetransform(This.sharedpagewidth/2,;
This.sharedpageheight/2)
This.ogdigraphics.rotatetransform(-45)
This.ogdigraphics.translatetransform(-This.sharedpagewidth/2,;
-This.sharedpageheight/2)
This.ogdigraphics.drawstring("Rotated Text" +CHR(13)+CHR(10)+;
"GDIPlus-X is COOL !!!", ;
lofont, lobrush, lorect, lostringformat)
* Reset Rotation
This.ogdigraphics.resettransform
This.NewPage = .F.
ENDIF
ENDWITH
DODEFAULT(nfrxrecno,;
nleft,ntop,nwidth,nheight,;
nobjectcontinuationtype, ;
ccontentstoberendered, gdiplusimage)
ENDPROC
ENDDEFINE
UPDATE 06-08-31
To make sure that the watermark will not be overwritten by opaque controls, the code below does the same thing shown above, but this time draws the watermark only after the footer band is totally rendered. The color used for this case was also changed from opaque to semitransparent, using Alpha of 128 ( 0 = totally transparent, 255 = opaque). So, here's the new ReportListener subclass to deal with this problem:
DEFINE CLASS myreportlistener AS _reportlistener OF ;
ADDBS(HOME()) + "FFC\" + "_ReportListener.VCX"
ogdigraphics = NULL
FUNCTION BEFOREREPORT
DODEFAULT()
This.ogdigraphics = _Screen.System.Drawing.Graphics.New()
ENDFUNC
FUNCTION AFTERBAND(nbandobjcode, nfrxrecno)
*-- FRX OBJCODE column values
#DEFINE FRX_OBJCOD_TITLE 0
#DEFINE FRX_OBJCOD_PAGEHEADER 1
#DEFINE FRX_OBJCOD_COLHEADER 2
#DEFINE FRX_OBJCOD_GROUPHEADER 3
#DEFINE FRX_OBJCOD_DETAIL 4
#DEFINE FRX_OBJCOD_GROUPFOOTER 5
#DEFINE FRX_OBJCOD_COLFOOTER 6
#DEFINE FRX_OBJCOD_PAGEFOOTER 7
#DEFINE FRX_OBJCOD_SUMMARY 8
#DEFINE FRX_OBJCOD_DETAILHEADER 9
#DEFINE FRX_OBJCOD_DETAILFOOTER 10
IF nbandobjcode==frx_objcod_pagefooter
IF NOT This.issuccessor
This.sharedgdiplusgraphics = This.GDIPLUSGRAPHICS
ENDIF
This.ogdigraphics.handle = This.sharedgdiplusgraphics
WITH _SCREEN.SYSTEM.drawing
* Create a SolidBrush with Red semi transparent color
LOCAL lobrush AS xfcbrush
lobrush = .solidbrush.new(.COLOR.fromArgb(128,255,128,128))
* Create a Rectangle in which the rotated text will be drawn
LOCAL lorect AS xfcrectangle
lorect = .rectangle.new(0, 0, This.sharedpagewidth,;
This.sharedpageheight)
* Get a basic string format object, then set properties
LOCAL lostringformat AS xfcstringformat
lostringformat = .stringformat.new()
lostringformat.ALIGNMENT = .stringalignment.CENTER
lostringformat.linealignment = .stringalignment.CENTER
* Create a Font object
LOCAL lofont AS xfcfont
lofont = .FONT.new("Verdana",48, 0, .graphicsunit.POINT)
* Translate and Rotate
This.ogdigraphics.translatetransform(This.sharedpagewidth/2,;
This.sharedpageheight/2)
This.ogdigraphics.rotatetransform(-45)
This.ogdigraphics.translatetransform(-This.sharedpagewidth/2,;
-This.sharedpageheight/2)
This.ogdigraphics.drawstring("Rotated Text" +CHR(13)+CHR(10)+;
"GDIPlus-X is COOL !!!", ;
lofont, lobrush, lorect, lostringformat)
* Reset Rotation
This.ogdigraphics.resettransform()
ENDWITH
ENDIF
DODEFAULT(nBandObjCode, nFRXRecNo)
ENDFUNC
ENDDEFINE
RELATED LINKS
Article from Bill Wagner http://www.ftponline.com/vsm/2002_10/online/csharp_bwagner_10_31_02/
GdiPlusX page in CodePlex: http://www.codeplex.com/Wiki/View.aspx?ProjectName=VFPX&title=GDIPlusX