WPF: Как сохранить элемент управления FrameworkElement() в виде изображения
Нужно сохранить какой-то элемент управления окна WPF в изображение. Допустим, сохранить как картинку динамически сгенерированный график или таблицу. Можно сделать это, например, так.
Сначала сгенерируем изображение с помощью класса RenderTargetBitmap(), запишем его в поток в памяти, прочитаем и сохраним в объект типа String():
''' <summary>
''' Генерирует строку, представляющую поток изображения, из FrameworkElement.
''' </summary>
''' <param name="elem">Элемент, который будет преобразован в изображение.</param>
Private Function GetElementAsString(ByVal elem As FrameworkElement) As String
Dim w As Integer = CInt(elem.ActualWidth)
Dim h As Integer = CInt(elem.ActualHeight)
Dim renderBitmap As New RenderTargetBitmap(w, h, 96, 96, PixelFormats.Default)
renderBitmap.Render(elem)
Dim pngEncoder As New PngBitmapEncoder()
Dim bmFrame As BitmapFrame = BitmapFrame.Create(renderBitmap)
pngEncoder.Frames.Add(bmFrame)
Dim pngStr As String = String.Empty
Using ms As New IO.MemoryStream()
pngEncoder.Save(ms)
ms.Seek(0, IO.SeekOrigin.Begin)
Using sr As New IO.StreamReader(ms, Text.Encoding.Default)
pngStr = sr.ReadToEnd
End Using
End Using
Return pngStr
End Function
Напишем метод для сохранения изображения в файл:
''' <summary>
''' Сохраняет строку с данными изображения в файл PNG с указанным именем.
''' </summary>
''' <param name="fileName">Имя файла с расширением PNG, под которым будет сохранено изображение.</param>
''' <param name="imgStr">Строка, представляющая изображение.</param>
Private Sub SaveElementAsImage(ByVal fileName As String, ByVal imgStr As String)
Using fs As New IO.FileStream(fileName, IO.FileMode.Create)
Using sw As New IO.StreamWriter(fs, Text.Encoding.Default)
sw.Write(imgStr)
End Using
End Using
End Sub
Теперь мы можем сохранить изображение в файл, используя предыдущие два метода:
Dim pngStr As String = GetElementAsString(MyControlToSave)
SaveElementAsImage("1.png", "Рисунок 1")
Кстати, интересно было бы иметь возможность менять размер сгенерированного изображения. Это пригодится, если нам нужно увеличить или уменьшить изображение элемента управления, или изменить его пропорции. Сделать это можно, например, вот таким образом:
''' <summary>
''' Изменяет размер переданного изображения.
''' </summary>
''' <param name="src">Исходное изображение.</param>
''' <param name="width">Ширина выходного изображения.</param>
''' <param name="height">Высота выходного изображения.</param>
Private Function GetResizedBitmapFrame(ByVal src As ImageSource, ByVal width As Double, ByVal height As Double) As BitmapFrame
Dim rect As New Rect(0, 0, width, height)
Dim group As New DrawingGroup
RenderOptions.SetBitmapScalingMode(group, BitmapScalingMode.HighQuality)
group.Children.Add(New ImageDrawing(src, rect))
Dim drwVisual As New DrawingVisual
Using drwContext = drwVisual.RenderOpen()
drwContext.DrawDrawing(group)
End Using
Dim resizedBitmap As New RenderTargetBitmap(CInt(width), CInt(height), 96, 96, PixelFormats.Default)
resizedBitmap.Render(drwVisual)
Return BitmapFrame.Create(resizedBitmap)
End Function
Теперь, чтобы использовать метод изменения размера изображения, нужно немного изменить наш метод GetElementAsString(), а именно, вместо
pngEncoder.Frames.Add(bmFrame)
добавить вот такой код:
Dim resizedFrame As BitmapFrame = GetResizedBitmapFrame(bmFrame, newWidth, newHeight) pngEncoder.Frames.Add(resizedFrame)
