RenderTargetBitmap不呈现包含的图像

时间:2015-09-09 14:29:48

标签: c# wpf image xaml

我想使用RenderTargetBitmap功能将XAML控件呈现给PNG文件。到目前为止,这很有效。

但是如果XAML包含任何图像,则这些图像不会在PNG文件中呈现。 这是我的XAML:

<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Name="LayoutRoot"
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  mc:Ignorable="d"
  d:DesignHeight="336"
  d:DesignWidth="336"
  Background="DarkGray">

<TextBlock Text="This is my Text"
           FontSize="35"
           HorizontalAlignment="Center" />
<Image Source="http://www.myurl.com/image.png"
       Height="200" /></Grid>

这是我的代码:

private BitmapSource RenderToBitmap(FrameworkElement target)
    {
        Rect bounds = VisualTreeHelper.GetDescendantBounds(target);
        RenderTargetBitmap renderBitmap = new RenderTargetBitmap((int)target.ActualWidth,
          (int)target.ActualHeight,
          96, 96, PixelFormats.Pbgra32);

        DrawingVisual visual = new DrawingVisual();
        using (DrawingContext context = visual.RenderOpen())
        {
            VisualBrush brush = new VisualBrush(target);
            context.DrawRectangle(brush, null, new Rect(new Point(), bounds.Size));
        }
        renderBitmap.Render(visual);
        return renderBitmap;
    }

还尝试使用像“/Assets/image.png”这样的参考图像和资源。每次在渲染的PNG文件中缺少图像时。

1 个答案:

答案 0 :(得分:2)

首先,您要渲染目标,但ImageControl异步加载BitmapSource,此时尚未准备就绪。如果您要等到ImageControl完成加载其源代码,您将得到您期望的结果。有趣的是,ImageControl在完成加载时不会通知您。

因此,短回答将是: 如果要将现有和已加载的可视化渲染到图像,只需等待嵌入的图像控件加载即可。

像这样:

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        img.LayoutUpdated += img_LayoutUpdated;
    }

    void img_LayoutUpdated(object sender, EventArgs e)
    {
        img.LayoutUpdated -= img_LayoutUpdated;
        var rt = RenderToBitmap(img);
        Save(rt);
    }

据我所知,没有简单的方法可以强制ImageControl加载其源代码。当ImageControl抛出“Loaded”事件时,并不意味着图像被加载。如果你有ImageControl.Source创建为BitmapImage,你可以做这样的事情:

            BitmapImage bi = new BitmapImage();
            bi.BeginInit();
            bi.DecodePixelHeight = 100;
            bi.CacheOption = BitmapCacheOption.OnLoad;
            bi.UriSource = new Uri(@"http://www.myurl.com/image.png");
            bi.EndInit();
            bi.DownloadCompleted += bi_DownloadCompleted; //will be ready to be saved to image when event will fire
            img.Source = bi;

或者像这样自己下载图片

    WebClient wc = new WebClient();
    using (MemoryStream stream = new MemoryStream(wc.DownloadData(@"http://www.google.ru/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png")))
    {
        BitmapImage myBitmapImage = new BitmapImage();
        myBitmapImage.BeginInit();
        myBitmapImage.StreamSource = stream;
        myBitmapImage.DecodePixelWidth = 200;
        myBitmapImage.EndInit();
        img.Source = myBitmapImage;
        // ready to be saved to image
    }

但在我看来,它并不适合你

如果您的目的是在内存中呈现视觉效果,那么您应该看看这个问题: Drawing a WPF UserControl with DataBinding to an Image