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

时间:2010-12-30 05:11:44

标签: c# wpf mvvm c#-4.0

我有searched并了解如何使用BmpBitmapEncoder在WPF中保存图像。我的程序有一个MVVM视图,我想保存为图像。是否可以将其设置为BitmapFrame,以便对其进行编码?如果是的话,是否有在线教程?

下面列出了我要保存的视图。

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

OverallView是用户控件。


如果无法将视图设置为BitmapFrame,可以将哪些wpf元素设置为BitmapSource/Frame

2 个答案:

答案 0 :(得分:19)

您可以将其作为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 =&gt;结果

答案 1 :(得分:0)

对上面已接受的答案表示敬意,因为它使我走上了解决之路,但这实际上使要求变得过于复杂。具体来说,您无需创建DrawingVisual即可传递给Render调用。您可以直接传递视图,因为它已经是Visual调用接受的Render

这是一个简化的版本,我也将其更改为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),因此您也可以直接将其设置为Source控件的Image属性,就像这样...

someImage.Source = someFrameworkElement.CopyAsBitmap();