Expiring Today—Celebrate National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

Scaling a WPF Generated bitmap based on XAML

Posted on 2008-10-21
1
Medium Priority
?
2,831 Views
Last Modified: 2013-11-12
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

Open in new window

0
Comment
Question by:TSmooth
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
1 Comment
 
LVL 16

Accepted Solution

by:
TSmooth earned 0 total points
ID: 22780755
Below is the code that did the trick. Took a long time to figure all of the dimensions out but I'm glad I got it working. Thanks to anyone who looked into this.
Public Sub Capture(ByVal MyImage As Canvas)
        ' Normally we would obtain a user's configured DPI setting to account for the possibilty of a high DPI setting. 
        ' However, this code is running server side so the client's DPI is not obtainable.
        Const SCREEN_DPI As Double = 96.0   ' Screen DPI
        Const TARGET_DPI As Double = 300.0  ' Print Quality DPI
 
        ' Determine the constraining scale to maintain the aspect ratio and the bounds of the image size
        Dim scale As Double = Math.Min(Width * SCREEN_DPI / MyImage.Width, Height * SCREEN_DPI / MyImage.Height)
 
        ' Setup the bounds of the image
        Dim bounds As Rect = New Rect(0, 0, MyImage.Width * scale, MyImage.Height * scale)
        MyImage.Measure(New Size(MyImage.Width * scale, MyImage.Height * scale))
        MyImage.Arrange(bounds)
 
        ' Create the target bitmap
        Dim rtb As RenderTargetBitmap = New RenderTargetBitmap(CDbl(MyImage.Width * scale / SCREEN_DPI * TARGET_DPI), CDbl(MyImage.Height * scale / SCREEN_DPI * TARGET_DPI), TARGET_DPI, TARGET_DPI, 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)
            ctx.DrawRectangle(vb, Nothing, New Rect(New System.Windows.Point(), bounds.Size))
        End Using
        ' Transform the visual to scale the image to our desired size.
        'dv.Transform = New ScaleTransform(scale, scale)
 
        ' Render the visual to the bitmap.
        rtb.Render(dv)
 
        ' Encode the image in the format selected. If no valid format was selected, default to png.
        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()
            Case Else
                encoder = New System.Windows.Media.Imaging.PngBitmapEncoder()
        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

Open in new window

0

Featured Post

Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

IntroductionWhile developing web applications, a single page might contain many regions and each region might contain many number of controls with the capability to perform  postback. Many times you might need to perform some action on an ASP.NET po…
Introduction This article shows how to use the open source plupload control to upload multiple images. The images are resized on the client side before uploading and the upload is done in chunks. Background I had to provide a way for user…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
In this brief tutorial Pawel from AdRem Software explains how you can quickly find out which services are running on your network, or what are the IP addresses of servers responsible for each service. Software used is freeware NetCrunch Tools (https…

719 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question