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)