Set dinamyc image to MapLayer marker
Hi there
I have a calculated field in SSRS 2008 R2 DataSet which shows a rotated image based on text and rotation angle.
If I use a Tablix, I can view the list of Texts and next to it the representing rotated image, using an Image component inside the cell.
It works perfect but when I assign the calculated image field to a MapPointLayer Marker Image, as Database source, it only shows the first element found and repeats it in every point.
Please help me ! I tried everything !Ivan
May 17th, 2011 7:42pm
In order to better explain my problem:
I have a SQL Server Spatial table with Geometry field represented as points, with street names and rotation angle in degrees (0 - 360º).
I want to display the street names in SSRS 2008 R2 Map and the street names have to be rotated by rotation angle specified in table.
I added the following code into the report to rotate text and convert it to image as described here:
http://geeks.ms/blogs/fangarita/archive/2010/10/06/code-sample-generando-im-225-genes-c-243-digos-de-barras-en-reporting-services.aspx
Public Class TextImage
Private Shared d_fontFamily As String = "Arial"
Private Shared d_fontSize As Integer = 10
Private Shared d_bold As Boolean = False
Private Shared d_italic As Boolean = False
Private Shared d_color As String = "Black"
Private Shared d_bgColor As String = "Transparent"
Private Shared d_rotation As Integer = 0
Private Shared d_underlineWidth As Integer = 0
Private Shared d_underlineColor As String = "Black"
Private Shared d_usePng As Boolean = False
Public ReadOnly Property IsReusable() As Boolean
Get
Return True
End Get
End Property
Public Function ImageToBase64(ByVal image As System.Drawing.Image, ByVal format As System.Drawing.Imaging.ImageFormat) As String
Using ms As New System.IO.MemoryStream
' Convert Image to byte[]
image.Save(ms, format)
Dim imageBytes As Byte()
imageBytes = ms.ToArray()
' Convert byte[] to Base64 String
Dim base64String As String
base64String = Convert.ToBase64String(imageBytes)
Return base64String
End Using
End Function
Public Shared Function Bytes2Image(ByVal bytes() As Byte) As System.Drawing.Image
If bytes Is Nothing Then
Return Nothing '
End If
Dim ms As New System.IO.MemoryStream(bytes)
Dim bm As System.Drawing.Bitmap = Nothing
Try
bm = New System.Drawing.Bitmap(ms)
Catch ex As Exception
System.Diagnostics.Debug.WriteLine(ex.Message)
End Try
Return bm
End Function
Public Function CreateTextImage(ByVal text As String, ByVal fontFamily As String, ByVal fontSize As Integer, ByVal bold As Boolean, ByVal italic As Boolean, ByVal color As String, ByVal bgColor As String, ByVal rotation As Integer, ByVal underlineWidth As Integer, ByVal underlineColor As String, ByVal usePng As Boolean) As Byte()
Dim textWidth As Single = 0
Dim textHeight As Single = 0
Dim fontStyle As System.Drawing.FontStyle = System.Drawing.FontStyle.Regular
If bold Then fontStyle = fontStyle Or Drawing.FontStyle.Bold
If italic Then fontStyle = fontStyle Or Drawing.FontStyle.Italic
Using font As New System.Drawing.Font(fontFamily, fontSize, fontStyle)
' Get the text measurements.
' I need to create a dummy bitmap so that I can get a Graphics object to get the text measurements.
Using bitmap As New System.Drawing.Bitmap(1, 1)
Using graphics As System.Drawing.Graphics = System.Drawing.Graphics.FromImage(bitmap)
textWidth = graphics.MeasureString(text, font).Width
textHeight = graphics.MeasureString(text, font).Height
End Using
End Using
' Calculate the needed bitmap measurements based on the text measurements.
Dim bitmapWidth As Integer = GetRotatedRectangleWidth(textWidth, textHeight, rotation)
Dim bitmapHeight As Integer = GetRotatedRectangleHeight(textWidth, textHeight, rotation)
' Now I create the real bitmap of the necessary size to fit the text.
Using bitmap As New System.Drawing.Bitmap(bitmapWidth, bitmapHeight)
Using graphics As System.Drawing.Graphics = System.Drawing.Graphics.FromImage(bitmap)
If (Not usePng) Then graphics.Clear(System.Drawing.Color.FromArgb(255, 255, 255, 204)) 'Color.FromArgb(&HFF, &HFF, &HFF, &HCC)
' Since I will be rotating text, I need to move the rotation point using the TranslateTransform.
Dim x As Integer, y As Integer
' But first I need to know the location of the rotation point.
GetXY(rotation, textWidth, textHeight, x, y)
graphics.TranslateTransform(x, y)
' Now rotate and draw the text.
graphics.RotateTransform(rotation)
' Fill in the background color
Using brush As New System.Drawing.SolidBrush(System.Drawing.ColorTranslator.FromHtml(bgColor))
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality
graphics.FillRectangle(brush, 0, 0, textWidth, textHeight)
End Using
graphics.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAlias
Using brush As New System.Drawing.SolidBrush(System.Drawing.ColorTranslator.FromHtml(color))
graphics.DrawString(text, font, brush, 0, 0)
End Using
If (underlineWidth > 0) Then
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality
Using pen As New System.Drawing.Pen(System.Drawing.ColorTranslator.FromHtml(underlineColor), underlineWidth)
graphics.DrawLine(pen, 0, textHeight, textWidth, textHeight)
End Using
End If
graphics.Flush()
Dim m As New System.IO.MemoryStream()
If usePng Then
bitmap.Save(m, System.Drawing.Imaging.ImageFormat.Png)
Else
bitmap.Save(m, System.Drawing.Imaging.ImageFormat.Gif)
End If
If (usePng) Then
Return m.ToArray()
Else
' transparency hack.
Dim n As Byte() = {}
n = m.ToArray()
n(787) = 254
Return n
End If
End Using ' using graphics
End Using ' using bitmap
End Using ' using font
End Function
Private Sub GetXY(ByVal rotation As Integer, ByVal tw As Single, ByVal th As Single, ByRef xT As Integer, ByRef yT As Integer)
xT = 0
yT = 0
Dim radians As Double = GetRadians(GetReferenceAngleForPositioning(rotation))
If (rotation >= 0 AndAlso rotation <= 90) Then
xT = Convert.ToInt32(Math.Sin(radians) * th)
ElseIf (rotation > 90 AndAlso rotation <= 180) Then
xT = Convert.ToInt32((Math.Sin(radians) * tw) + (Math.Cos(radians) * th))
yT = Convert.ToInt32(Math.Sin(radians) * th)
ElseIf (rotation > 180 AndAlso rotation <= 270) Then
xT = Convert.ToInt32(Math.Cos(radians) * tw)
yT = Convert.ToInt32((Math.Cos(radians) * th) + (Math.Sin(radians) * tw))
Else
yT = Convert.ToInt32(Math.Sin(radians) * tw)
End If
End Sub
Private Function GetRotatedRectangleWidth(ByVal width As Single, ByVal height As Single, ByVal rotation As Integer) As Integer
Return GetRotatedRectangleWidth(width, height, GetRadians(GetReferenceAngleForSizing(rotation)))
End Function
Private Function GetRotatedRectangleWidth(ByVal width As Single, ByVal height As Single, ByVal rotationInRadians As Double) As Integer
Dim w1 As Double = width * Math.Cos(rotationInRadians)
Dim w2 As Double = height * Math.Sin(rotationInRadians)
Return Convert.ToInt32(Math.Ceiling(w1 + w2))
End Function
Private Function GetRotatedRectangleHeight(ByVal width As Single, ByVal height As Single, ByVal rotation As Integer) As Integer
Return GetRotatedRectangleHeight(width, height, GetRadians(GetReferenceAngleForSizing(rotation)))
End Function
Private Function GetRotatedRectangleHeight(ByVal width As Single, ByVal height As Single, ByVal rotationInRadians As Double)
Dim h1 As Double = width * Math.Sin(rotationInRadians)
Dim h2 As Double = height * Math.Cos(rotationInRadians)
Return Convert.ToInt32(Math.Ceiling(h1 + h2))
End Function
Private Function GetRadians(ByVal referenceAngle As Double) As Double
Return Math.PI * referenceAngle / 180.0
End Function
' The only difference between the reference angles for sizing and positioning is in the 3rd quadrant (> 90 <= 180).
Private Function GetReferenceAngleForSizing(ByVal rotationInDegrees As Integer) As Double
If (rotationInDegrees >= 0 And rotationInDegrees <= 90) Then
Return rotationInDegrees
ElseIf (rotationInDegrees > 90 And rotationInDegrees <= 180) Then
Return 180 - rotationInDegrees
ElseIf (rotationInDegrees > 180 And rotationInDegrees <= 270) Then
Return rotationInDegrees - 180
ElseIf (rotationInDegrees > 270 And rotationInDegrees <= 360) Then
Return 360 - rotationInDegrees
Else
Return rotationInDegrees
End If
End Function
Private Function GetReferenceAngleForPositioning(ByVal rotationInDegrees As Integer) As Double
If (rotationInDegrees >= 0 And rotationInDegrees <= 90) Then
Return rotationInDegrees
ElseIf (rotationInDegrees > 90 And rotationInDegrees <= 180) Then
Return rotationInDegrees - 90
ElseIf (rotationInDegrees > 180 And rotationInDegrees <= 270) Then
Return rotationInDegrees - 180
ElseIf (rotationInDegrees > 270 And rotationInDegrees <= 360) Then
Return 360 - rotationInDegrees
Else
Return rotationInDegrees
End If
End Function
End Class
Then I added a DataSet (from SQL Spatial DataSource) to the report:
SELECT OID, TEXTSTRING, TEXT_ANGLE, GEO
FROM STREET
and added a calculated field to the dataset:
FIELD NAME: IMAGE
FIELD VALUE: =Convert.ToBase64String(Code.txtImg.CreateTextImage(Fields!TEXTSTRING.Value,
"Arial", 10,
false,
false,
"Blue",
"Transparent",Fields!TEXT_ANGLE.Value, 0,
"Blue",
true))
So far it works fine, the IMAGE calculated field displays an image representing the street name (TEXTSTRING field) with rotation angle (TEXT_ANGLE field)
If I put an Image component into a Tablix component, I can view the rotated text as I want. I set the Image properties like this:
Source: DataBase
Field: =Fields!IMAGE.Value
MIME Type: image/png
The problem is when I assign the IMAGE field to a Map Point Layer and set Marker properties like this:
Marker Type: Image
Image Source: DataBase
Field: =Fields!IMAGE.Value
MIME Type: image/png
It shows the First Marker found in dataset and repeats it in every Point image marker. I need that each Marker change to the corresponding TEXTSTRING but cannot figure it out how.
Please help me !
PD: Sorry for my bad english, hope you understand what I wrote.
Ivan
Free Windows Admin Tool Kit Click here and download it now
May 18th, 2011 10:25am