Background: I'm working on a silverlight (1.0) application that dynamically builds a map of the United States with icons and text overlayed at specific locations. The map works great in the browser and now I need to get a static (printable and insertable into documents/powerpoints) copy of a displayed map.
Objective: In order to get a printable copy of the map that can also be used in powerpoint slides, word, etc. I've chosen to create an ASP.NET HttpHandler to recreate the xaml on the server side in WPF and then render the WPF to a bitmap image which is returned as a png file, generated at 300dpi for better print quality.
Problem: This works great with one problem, I can't get the image to scale to a specified size. I've tried several different things, some of which can be seen in the commented out lines. I need to be able to specify a height and width of the image, either in inches or pixels, I don't necessarily care which, and have the xaml scale to that size for the generated bitmap. Currently, if I make the size bigger than the root canvas, the canvas gets rendered at its original size in the top left corner of the generated image at the size specified. Below is the important part of my httphandler. The root canvas stored as "MyImage" has a Height of 600 and a Width of 800. What am I missing to get the content to scale to fit the size specified?
I don't fully understand what the dimensions being passed into Arrange() and Measure() do as some of this code was taken from online examples. I also don't fully understand the RenderTargetBitmap stuff. Any guidance would be appreciated.
Public Sub Capture(ByVal MyImage As Canvas) ' Determine the constraining scale to maintain the aspect ratio and the bounds of the image size Dim scale As Double = Math.Min(Width / MyImage.Width, Height / MyImage.Height)
'Dim vbox As New Viewbox()
'vbox.Stretch = Stretch.Uniform
'vbox.StretchDirection = StretchDirection.Both
'vbox.Height = Height * scale * 300 / 96.0
'vbox.Width = Width * scale * 300 / 96.0
'vbox.Child = MyImage
Dim bounds As Rect = New Rect(0, 0, MyImage.Width * scale, MyImage.Height * scale)
MyImage.Measure(New Size(Width * scale, Height * scale))
MyImage.Arrange(bounds)
'MyImage.UpdateLayout()
' Create the target bitmap
Dim rtb As RenderTargetBitmap = New RenderTargetBitmap(CInt(Width * scale * 300 / 96.0), CInt(Height * scale * 300 / 96.0), 300, 300, PixelFormats.Pbgra32)
' Render the image to the target bitmap
Dim dv As DrawingVisual = New DrawingVisual()
Using ctx As DrawingContext = dv.RenderOpen()
Dim vb As New VisualBrush(MyImage)
'Dim vb As New VisualBrush(vbox)
ctx.DrawRectangle(vb, Nothing, New Rect(New System.Windows.Point(), bounds.Size))
End Using
rtb.Render(dv)
' Encode the image in the format selected
Dim encoder As System.Windows.Media.Imaging.BitmapEncoder
Select Case Encoding.ToLower
Case "jpg"
encoder = New System.Windows.Media.Imaging.JpegBitmapEncoder()
Case "png"
encoder = New System.Windows.Media.Imaging.PngBitmapEncoder()
Case "gif"
encoder = New System.Windows.Media.Imaging.GifBitmapEncoder()
Case "bmp"
encoder = New System.Windows.Media.Imaging.BmpBitmapEncoder()
Case "tif"
encoder = New System.Windows.Media.Imaging.TiffBitmapEncoder()
Case "wmp"
encoder = New System.Windows.Media.Imaging.WmpBitmapEncoder()
End Select
encoder.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create(rtb))
' Create the memory stream to save the encoded image.
retImageStream = New System.IO.MemoryStream()
encoder.Save(retImageStream)
retImageStream.Flush()
retImageStream.Seek(0, System.IO.SeekOrigin.Begin)
MyImage = Nothing
End Sub