C# 无窗口位图的WPF渲染控件

C# 无窗口位图的WPF渲染控件,c#,wpf,C#,Wpf,因此,我们有一个WPF应用程序,它显示了使用Live charts库创建的一些图表。然而,我得到的任务是在后台渲染图表,并将它们保存到PNG图像中,而不显示WPF窗口。我在网上找到了一篇文章,它采用了UserControl,并且确实做到了这一点,但我自己尝试了一下,只得到了80×50像素的透明图像 不幸的是,我不太熟悉渲染的WPF内部,因此非常感谢您的帮助。这是我的代码,用LiveChart本身最简单的图表示例呈现到最低限度 using System; using System.IO; usin

因此,我们有一个WPF应用程序,它显示了使用Live charts库创建的一些图表。然而,我得到的任务是在后台渲染图表,并将它们保存到PNG图像中,而不显示WPF窗口。我在网上找到了一篇文章,它采用了UserControl,并且确实做到了这一点,但我自己尝试了一下,只得到了80×50像素的透明图像

不幸的是,我不太熟悉渲染的WPF内部,因此非常感谢您的帮助。这是我的代码,用LiveChart本身最简单的图表示例呈现到最低限度

using System;
using System.IO;
using System.Windows.Media;
using System.Windows.Media.Imaging;

using LiveCharts.Wpf;
using LiveCharts.Geared;
using LiveCharts;

namespace Screenshot2Pdf {
    class Program {
        [STAThread]
        static void Main(string[] args) {
            var Series = new SeriesCollection();
            var r = new Random();

            for (var i = 0; i < 30; i++) // 30 series
            {
                var trend = 0d;
                var values = new double[10000];

                for (var j = 0; j < 10000; j++) // 10k points each
                {
                    trend += (r.NextDouble() < .8 ? 1 : -1) * r.Next(0, 10);
                    values[j] = trend;
                }

                var series = new LineSeries {
                    Values = values.AsGearedValues().WithQuality(Quality.Low),
                    Fill = Brushes.Transparent,
                    StrokeThickness = .5,
                    PointGeometry = null //use a null geometry when you have many series
                };

                Series.Add(series);
            }

            var chart = new CartesianChart();

            chart.Series = Series;

            chart.BeginInit();
            chart.EndInit();

            // Measure and arrange the tile
            chart.Measure(new System.Windows.Size {
                Height = double.PositiveInfinity,
                Width = double.PositiveInfinity
            });
            chart.Arrange(new System.Windows.Rect(0, 0,
               chart.DesiredSize.Width,
               chart.DesiredSize.Height));

            chart.UpdateLayout();

            RenderTargetBitmap rtb = new RenderTargetBitmap((int)chart.DesiredSize.Width, (int)chart.DesiredSize.Height, 96, 96, PixelFormats.Pbgra32);
            rtb.Render(chart);

            PngBitmapEncoder png = new PngBitmapEncoder();
            png.Frames.Add(BitmapFrame.Create(rtb));
            MemoryStream stream = new MemoryStream();
            png.Save(stream);
            var image = System.Drawing.Image.FromStream(stream);

            image.Save(@"D:\bitmap.png");
        }
    }
}
使用系统;
使用System.IO;
使用System.Windows.Media;
使用System.Windows.Media.Imaging;
使用LiveCharts.Wpf;
使用动态图表;
使用动态图表;
命名空间截图2PDF{
班级计划{
[状态线程]
静态void Main(字符串[]参数){
var系列=新系列集合();
var r=新的随机变量();
对于(var i=0;i<30;i++)//30系列
{
var趋势=0d;
var值=新的双精度[10000];
对于(var j=0;j<10000;j++)//10k点
{
趋势+=(r.NextDouble()<.8?1:-1)*r.Next(0,10);
数值[j]=趋势;
}
var系列=新系列{
Values=Values.AsGearedValues().带质量(质量.低),
填充=画笔。透明,
冲程厚度=.5,
PointGeometry=null//当有多个系列时,请使用null几何体
};
系列。添加(系列);
}
var图表=新的CartesianChart();
图表系列=系列;
chart.BeginInit();
chart.EndInit();
//测量并排列瓷砖
图表.度量(新System.Windows.Size){
高度=双正不确定性,
宽度=double.PositiveInfinity
});
chart.Arrange(新系统.Windows.Rect(0,0,,
chart.DesiredSize.Width,
图表(所需尺寸、高度);
chart.UpdateLayout();
RenderTargetBitmap rtb=新的RenderTargetBitmap((int)chart.DesiredSize.Width,(int)chart.DesiredSize.Height,96,96,PixelFormats.Pbgra32);
渲染(图表);
PngBitmapEncoder png=新的PngBitmapEncoder();
png.Frames.Add(BitmapFrame.Create(rtb));
MemoryStream stream=新的MemoryStream();
保存(流);
var image=System.Drawing.image.FromStream(stream);
image.Save(@“D:\bitmap.png”);
}
}
}

好吧,我不知道为什么。如前所述,我不太熟悉WPF的内部渲染机制以及触发它的原因,但解决方案是将图表包装在一个Viewbox中。下面的代码实现了这一点:

        var viewbox = new Viewbox();
        viewbox.Child = chart;
        viewbox.Measure(chart.RenderSize);
        viewbox.Arrange(new Rect(new Point(0, 0), chart.RenderSize));
        chart.Update(true, true); //force chart redraw
        viewbox.UpdateLayout();

        // RenderTargetBitmap rtb = new RenderTargetBitmap((int)chart.DesiredSize.Width, (int)chart.DesiredSize.Height, 96, 96, PixelFormats.Pbgra32);
        var rtb = new RenderTargetBitmap(500, 500, 96, 96, PixelFormats.Default);
        rtb.Render(chart);

        var encoder = new PngBitmapEncoder();
        encoder.Frames.Add(BitmapFrame.Create(rtb));

        using (var stream = File.OpenWrite(@"D:\bitmap.png")) {
            encoder.Save(stream);
        }

完全相同的代码,但在WPF窗口中呈现,会产生一个更大的图像(也明显没有拉伸),并且不是透明的,但背景为白色。将断点放在图表上。Arrange显示desiredsize也是80*50。这只会生成一个透明图像。只是更大。只是使用LiveCharts中最基本的示例。我不知道LiveCharts,但由于您在LineSeries上设置了
Fill=brushs.Transparent
,因此您可能还应该将
Stroke
设置为非空和非透明。在窗口应用程序中,可能存在默认样式设置的特性值,但在您的应用程序中没有设置。