【问题标题】:Save wpf view as image, preferably .png将 wpf 视图保存为图像,最好是 .png
【发布时间】:2010-12-30 05:11:43
【问题描述】:

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

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

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

OverallView 是一个用户控件。


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

【问题讨论】:

标签: c# wpf mvvm c#-4.0


【解决方案1】:

您可以将其返回为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);   
}

修复:位图 => 结果

【讨论】:

  • 将位图更改为结果。除此之外,它很好。
  • src 参数可以是BitmapSource 以使其更广泛地使用。此外,编码器本地变量应声明为 var imho。
  • 我不知道如何调用这些方法,谁能解释一下?谢了。
  • @Denis,你可以在下面看到我的回答。上面有我已经删除的不必要的逻辑。我还把它做成了一个扩展方法,并通过示例向您展示了如何使用它们。
【解决方案2】:

感谢上面接受的答案,因为它引导我找到解决方案,但这实际上使要求过于复杂。具体来说,您无需创建DrawingVisual 即可传递给Render 调用。您可以直接传递视图,因为它已经是 VisualRender 调用接受它。

这是一个简化版本,我还在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();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-10-16
    • 1970-01-01
    • 1970-01-01
    • 2014-10-05
    • 2011-03-07
    • 2011-01-19
    • 2012-01-02
    相关资源
    最近更新 更多