保存wpf视图为图像,最好是.png

wecizke3  于 2023-10-22  发布在  其他
关注(0)|答案(2)|浏览(94)

我已经搜索并了解如何使用BmpBitmapEncoder在WPF中保存图像。我的程序有一个MVVM视图,我想保存为图像。是否可以将其设置为BitmapFrame,以便进行编码?如果有,有在线教程吗?
下面列出的是我要保存的视图。

<Grid>
    <view:OverallView Grid.Row="1"
        Visibility="{Binding IsOverallVisible,Converter={StaticResource B2VConv}}" />
</Grid>

OverallView是一个用户控件。
如果不能将视图设置为BitmapFrame,那么哪些wpf元素可以设置为BitmapSource/Frame

vddsk6oq

vddsk6oq1#

您可以将其返回为RenderTargetBitmap

public static RenderTargetBitmap GetImage(OverallView view)
{
    Size size = new Size(view.ActualWidth, view.ActualHeight);
    if (size.IsEmpty)
        return null;

    RenderTargetBitmap result = new RenderTargetBitmap((int)size.Width, (int)size.Height, 96, 96, PixelFormats.Pbgra32);

    DrawingVisual drawingvisual = new DrawingVisual();
    using (DrawingContext context = drawingvisual.RenderOpen())
    {
        context.DrawRectangle(new VisualBrush(view), null, new Rect(new Point(), size));
        context.Close();
    }

    result.Render(drawingvisual);
    return result;
}

之后,您可以使用PngBitmapEncoder将其保存为PNG并将其保存到流中,例如:

public static void SaveAsPng(RenderTargetBitmap src, Stream outputStream)
{
    PngBitmapEncoder encoder = new PngBitmapEncoder();
    encoder.Frames.Add(BitmapFrame.Create(src));

    encoder.Save(outputStream);   
}

FIX:bitmap => result

goqiplq2

goqiplq22#

感谢上面的公认答案引导我找到了解决方案,但这实际上使需求过于复杂。具体来说,您不需要创建DrawingVisual来传递给Render调用。您可以直接传递视图,因为它已经是Render调用接受的Visual
下面是一个简化的版本,我也将其更改为FrameworkElement上的扩展方法,因此您可以轻松地将其用于任何控件。
注意:虽然Render接受Visual,但是你不能扩展Visual,因为你需要实际的宽度和高度来创建RenderTargetBitmap,但是出于同样的原因,你可能已经在使用FrameworkElement了。

public static RenderTargetBitmap? CopyAsBitmap(this FrameworkElement frameworkElement) {

    var targetWidth  = (int)frameworkElement.ActualWidth;
    var targetHeight = (int)frameworkElement.ActualHeight;

    // Exit if there's no 'area' to render
    if (targetWidth == 0 || targetHeight == 0)
        return null;

    // Prepare the rendering target
    var result = new RenderTargetBitmap(targetWidth, targetHeight, 96, 96, PixelFormats.Pbgra32);

    // Render the framework element into the target
    result.Render(frameworkElement);

    return result;
}

然后我有第二个扩展方法,它接受任何BitmapSourceRenderTargetBitmap是它的子类),并根据提供的编码器返回字节。

public static byte[] Encode(this BitmapSource bitmapSource, BitmapEncoder bitmapEncoder){

    // Create a 'frame' for the BitmapSource, then add it to the encoder
    var bitmapFrame = BitmapFrame.Create(bitmapSource);
    bitmapEncoder.Frames.Add(bitmapFrame);

    // Prepare a memory stream to receive the encoded data, then 'save' into it
    var memoryStream = new MemoryStream();
    bitmapEncoder.Save(memoryStream);
    
    // Return the results of the stream as a byte array
    return memoryStream.ToArray();
}

这就是你如何一起使用它。以下代码将任何FrameworkElement渲染为PNG:

var renderTargetBitmap = someFrameworkElement.CopyAsBitmap();
var pngData = renderTargetBitmap.Encode(new PngBitmapEncoder());
File.WriteAllBytes(@"C:\Users\SomeUser\Desktop\TestOutput.png", pngData);

或者更流畅地说...

var pngData = someFrameworkElement
    .CopyAsBitmap()
    .Encode(new PngBitmapEncoder());

File.WriteAllBytes(@"C:\Users\SomeUser\Desktop\TestOutput.png", pngData);

要将其渲染为JPG,只需更改编码器,就像这样...

var jpegData = someFrameworkElement
    .CopyAsBitmap()
    .Encode(new JpegBitmapEncoder());

File.WriteAllBytes(@"C:\Users\SomeUser\Desktop\TestOutput.jpg", jpegData);

此外,由于RenderTargetBitmap最终是ImageSource(通过BitmapSource),因此您也可以直接将其设置为Image控件的Source属性,如下所示。

someImage.Source = someFrameworkElement.CopyAsBitmap();

相关问题