代码之家  ›  专栏  ›  技术社区  ›  Tom

在渲染为位图之前缩放WPF内容

  •  9
  • Tom  · 技术社区  · 16 年前

    背景 我正在开发一个silverlight(1.0)应用程序,该应用程序动态构建美国地图,在特定位置叠加图标和文本。该地图在浏览器中运行良好,现在我需要获得显示地图的静态(可打印并可插入到文档/幻灯片中)副本。

    目标: 为了获得地图的可打印副本,该副本也可用于powerpoint幻灯片、word等。我选择创建一个ASP。NET HttpHandler在WPF的服务器端重新创建xaml,然后将WPF渲染为位图图像,该图像以png文件的形式返回,以300dpi的分辨率生成,以获得更好的打印质量。

    问题: 这很好地解决了一个问题,我无法将图像缩放到指定的大小。我尝试了几种不同的方法,其中一些可以在评论中看到。我需要能够指定图像的高度和宽度,以英寸或像素为单位,我不一定在乎哪一个,并将生成的位图的xaml比例设置为该大小。目前,如果我将大小设置为大于根画布,画布将以指定的大小在生成图像的左上角以原始大小渲染。下面是我的httphandler的重要部分。存储为“MyImage”的根画布的高度为600,宽度为800。为了使内容缩放到指定的大小,我缺少什么?

    我并不完全理解传递给Arrange()和Measure()的维度的作用,因为其中一些代码来自在线示例。我也不完全理解RenderTargetBitmap的东西。任何指导都将不胜感激。

    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
    
    2 回复  |  直到 9 年前
        1
  •  13
  •   Donnelle    16 年前

    这应该足以让你开始:

    
    private void ExportCanvas(int width, int height)
    {
        string path = @"c:\temp\Test.tif";
        FileStream fs = new FileStream(path, FileMode.Create);
    
    
        RenderTargetBitmap renderBitmap = new RenderTargetBitmap(width,
                                                                 height, 1/300, 1/300, PixelFormats.Pbgra32);
    
        DrawingVisual visual = new DrawingVisual();
        using (DrawingContext context = visual.RenderOpen())
        {
            VisualBrush brush = new VisualBrush(MyCanvas);
            context.DrawRectangle(brush,
                                  null,
                                  new Rect(new Point(), new Size(MyCanvas.Width, MyCanvas.Height)));
        }
    
        visual.Transform = new ScaleTransform(width / MyCanvas.ActualWidth, height / MyCanvas.ActualHeight);
    
        renderBitmap.Render(visual);
    
        BitmapEncoder encoder = new TiffBitmapEncoder();
        encoder.Frames.Add(BitmapFrame.Create(renderBitmap));
        encoder.Save(fs);
        fs.Close();
    }
    
        2
  •  1
  •   Tom Tom    16 年前

    这就是最终为我工作的东西:

    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