Масштабирование содержимого WPF перед рендерингом в растровое изображение - PullRequest
9 голосов
/ 21 октября 2008

Справочная информация: Я работаю над приложением silverlight (1.0), которое динамически создает карту Соединенных Штатов с наложенными в определенных местах значками и текстом. Карта отлично работает в браузере, и теперь мне нужно получить статическую (печатаемую и вставляемую в документы / powerpoints) копию отображаемой карты.

Цель: Чтобы получить печатную копию карты, которая также может использоваться в слайдах PowerPoint, Word и т. Д. Я решил создать ASP.NET HttpHandler, чтобы воссоздать xaml на стороне сервера в WPF, а затем отобразить WPF в растровое изображение, которое возвращается в виде файла png, созданного с разрешением 300 точек на дюйм для лучшего качества печати.

Проблема: Это прекрасно работает с одной проблемой, я не могу увеличить изображение до указанного размера. Я пробовал несколько разных вещей, некоторые из которых можно увидеть в закомментированных строках. Мне нужно иметь возможность указать высоту и ширину изображения, в дюймах или пикселях, мне не все равно, какое значение, и иметь масштаб 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 ]

13 голосов
/ 22 октября 2008

Этого должно быть достаточно, чтобы начать:


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();
}
1 голос
/ 23 октября 2008

Вот что у меня получилось:

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...