Sunday, December 27, 2009

Tuesday, March 31, 2009

Thursday, January 8, 2009

SSRS Reports Rotate Text Or Split Alphabet Per Line

Few days ago my client requested a report, which required rotation of text and alphabet by 45 degree. Expected output was something Like this:

Many of you may know that you can rotate a text in textbox by setting WritingMode to "tb-rl", which will rotate the text and it will look something like this:

In order to rotate text at desired angle do following:
(1) create an image with desired text
(2) rotate that image
(3) import it to the image box in report

Add System.Drawing to the references by going to the Report Properties -> References.

for step1 use following function:
Function CreateImage(ByVal sImageText As String, ByVal FontType As String, ByVal FontSize As Integer) As System.Drawing.Bitmap
'Create an image from scratch
Dim bmpImage As New Drawing.Bitmap(1, 1)
Dim iWidth As Integer = 0
Dim iHeight As Integer = 0
'Create the Font object for the image text drawing.
Dim MyFont As New Drawing.Font(FontType, FontSize, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point)
'Create a graphics object to measure the text's width and height.
Dim MyGraphics As Drawing.Graphics = Drawing.Graphics.FromImage(bmpImage)
'This is where the bitmap size is determined.
iWidth = MyGraphics.MeasureString(sImageText, MyFont).Width
iHeight = MyGraphics.MeasureString(sImageText, MyFont).Height
'// Create the bmpImage again with the correct size for the text and font.
bmpImage = New Drawing.Bitmap(bmpImage, New Drawing.Size(iWidth, iHeight))
'// Add the colors to the new bitmap.
MyGraphics = Drawing.Graphics.FromImage(bmpImage)
MyGraphics.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAlias
MyGraphics.DrawString(sImageText, MyFont, New Drawing.SolidBrush(Drawing.Color.Black), 0, 0)
Return bmpImage
End Function

for step2 use following function:

Function RotateImage(ByVal bm_in As System.Drawing.Bitmap, ByVal RotationAngle As Integer) As System.Drawing.Bitmap
Dim wid As Single = bm_in.Width
Dim hgt As Single = bm_in.Height
Dim corners As System.Drawing.Point() = { _
New System.Drawing.Point(0, 0), _
New System.Drawing.Point(wid, 0), _
New System.Drawing.Point(0, hgt), _
New System.Drawing.Point(wid, hgt)}
' Translate to center the bounding box at the origin.
Dim cx As Single = wid / 2
Dim cy As Single = hgt / 2
Dim i As Long
For i = 0 To 3
corners(i).X -= cx
corners(i).Y -= cy
Next i
' Rotate.
Dim theta As Single = Single.Parse(RotationAngle) * System.Math.PI _
/ 180.0
Dim sin_theta As Single = System.Math.Sin(theta)
Dim cos_theta As Single = System.Math.Cos(theta)
Dim X As Single
Dim Y As Single
For i = 0 To 3
X = corners(i).X
Y = corners(i).Y
corners(i).X = X * cos_theta + Y * sin_theta
corners(i).Y = -X * sin_theta + Y * cos_theta
Next i
' Translate so X >= 0 and Y >=0 for all corners.
Dim xmin As Single = corners(0).X
Dim ymin As Single = corners(0).Y
For i = 1 To 3
If xmin > corners(i).X Then xmin = corners(i).X
If ymin > corners(i).Y Then ymin = corners(i).Y
Next i
For i = 0 To 3
corners(i).X -= xmin
corners(i).Y -= ymin
Next i
' Create an output Bitmap and Graphics object.
Dim bm_out As New System.Drawing.Bitmap(CInt(-2 * xmin), CInt(-2 * _
Dim gr_out As System.Drawing.Graphics = System.Drawing.Graphics.FromImage(bm_out)
' Drop the last corner lest we confuse DrawImage,
' which expects an array of three corners.
ReDim Preserve corners(2)
' Draw the result onto the output Bitmap.
gr_out.DrawImage(bm_in, corners)
' Display the result.
Return bm_out
End Function

for step3 use following function:

Function StreamImage(ByVal bmpImage As System.Drawing.Bitmap)
Dim stream As IO.MemoryStream = New IO.MemoryStream
Dim bitmapBytes As Byte()
'Create bitmap stream
bmpImage.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg)
bitmapBytes = stream.ToArray
Return bitmapBytes
End Function
Finally execute all together:
Use following code:
Function Create_RotateAndStreamImage(ByVal sImageText As String, ByVal FontType As String, ByVal FontSize As Integer, ByVal RotationAngle As Integer)
'Create a blank image
Dim bmpImage As New Drawing.Bitmap(1, 1)
'Create an image from scratch
bmpImage = CreateImage(sImageText, FontType, FontSize)
'Rotate Image at desired Angle
bmpImage = RotateImage(bmpImage, RotationAngle)
Return StreamImage(bmpImage)
Return bmpImage
End Function
It gives desired results
buy using following expression:

= Code.Create_RotateAndStreamImage("TEJAS", "Microsoft Sans Serif", 14, 45)

Incase some of you may want to get following outcome:

So, now you have to rotate the alphabets, there isn't a builtin function available to rotate alphabets.
Anohter way is do not rotate text, just split word in to aphabet per line. You can use "& vbCrLf & " in between two alphabet to go to next line.

I used following vb code to do that:
Public Function Split(Word As String) As String
Dim TempWord As String
Dim SplitTemp As String
Split = ""
TempWord = Word
Do While Len(TempWord) > 0
SplitTemp = Left(TempWord, 1)
Split = Split & vbCrLf & SplitTemp
TempWord = Right(TempWord, Len(TempWord) - 1)
End Function

And use following expression: