Set dynamic 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:26am

Hi, After a lot time of research to your scenario, I think you might select the option of Use default marker on Map Marker Type Rules Properties dialog box, actually, you should select the option of Visualize data by using markers, you should also select the datafield to match the image in your database, this is a must. Lastly, config below setting: Marker Type: Image Image Source: DataBase Field: =Fields!IMAGE.Value MIME Type: image/png Please remember to mark the replies as answers if they help and unmark them if they provide no help.
May 24th, 2011 3:27am

Hi, thanks for your attention. You're right, I was selecting the Use default marker option. Now, following your instructions I get in my map only one marker represented as a white circle. In Legend, I can see one street name rotated like I want, but only one. I dont know which datafield I should select to match the image. In fact the image isnt in database, the image is a calculated field in the same dataset that holds the Geometry field. This calculated field was made by the custom code in the second post. Do you have an idea of what I am missing ?Ivan
Free Windows Admin Tool Kit Click here and download it now
May 24th, 2011 9:58am

Hi carijona, You should create a field contain different values to identify different markers, with this field, can you match different images with different points.Please remember to mark the replies as answers if they help and unmark them if they provide no help.
May 31st, 2011 4:14am

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics