RenderTargetBitmap不渲染包含的图像 [英] RenderTargetBitmap does not render included images

查看:190
本文介绍了RenderTargetBitmap不渲染包含的图像的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用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文件中丢失图像时.

解决方案

首先发生的事情是渲染目标,但是ImageControl异步加载BitmapSource,但此时尚未准备好.如果您等到ImageControl完成加载其源代码,您将得到您所期望的.有趣的是,ImageControl在完成加载时不会通知您.

因此,简短的 answer 为: 如果您想将现有的和已经加载的视觉效果呈现给图像,只需等待加载嵌套的图像控件即可.

赞:

    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
    }

但是我认为这不太适合您

如果您的目的是在内存中呈现视觉效果,那么您应该看一下以下问题: 将具有数据绑定的WPF用户控件绘制到图像

I want to render an XAML control to a PNG file with the RenderTargetBitmap functionality. This works great so far.

But if the XAML contains any Images these images are not rendered in the PNG file. This is my 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>

And this is my code:

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;
    }

Also tried with referenced images like "/Assets/image.png" and as Resource. Every time the image is missing in the rendered PNG File.

解决方案

Firstly what happens is that you render your target, but your ImageControl loads BitmapSource asynchronously and isn't ready yet at that moment. If you would wait until ImageControl finishes loading its source you will get what you expect. Fun thing is, ImageControl doesn't inform you when it has finished loading.

So, short answer would be: If you want to render existing and already loaded visual to image, just wait until nested image controls are loaded.

Like this:

    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);
    }

As far as I know there is no easy way to force ImageControl to load its source. And when ImageControl throws "Loaded" event it doesn't mean that the image is loaded. If you would have you ImageControl.Source created as BitmapImage, you could have done something like this:

            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;

or download your image by yourself like this

    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
    }

But in my opinion it doesn't suit you well

If your purpose is to render visual in memory, then you should take a look at this question: Drawing a WPF UserControl with DataBinding to an Image

这篇关于RenderTargetBitmap不渲染包含的图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆