从具有 LiveChart 的 UserControl 渲染图像
Render image from UserControl that has LiveChart
我一直在渲染 window 中未显示的 UserControl 的 black/blank 图像。 UserControl 包含 LiveChart 的 CartesianChart 和一些 UIElement。首先我从 SO: C# chart to image with LiveCharts 借用解决方案
和 Github: Live-Charts/ChartToImageSample.xaml.cs 并在运行时生成的简单 UIControl 上应用 SaveToPng
和 EncodeVisual
(未在 window 中添加或显示),这有效。
Canvas control = new Canvas() { Width=100, Height=100, Background = new SolidColorBrush(Colors.Pink)};
control.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
control.Arrange(new Rect(0, 0, control.DesiredSize.Width, control.DesiredSize.Height));
control.UpdateLayout();
SaveToPng(control, @"C:\Foo.png");
private void SaveToPng(FrameworkElement visual, string fileName)
{
PngBitmapEncoder encoder = new PngBitmapEncoder();
EncodeVisual(visual, fileName, encoder);
}
private static void EncodeVisual(FrameworkElement visual, string fileName, BitmapEncoder encoder)
{
RenderTargetBitmap bitmap = new RenderTargetBitmap((int)visual.ActualWidth, (int)visual.ActualHeight, 96, 96, PixelFormats.Pbgra32);
bitmap.Render(visual);
BitmapFrame frame = BitmapFrame.Create(bitmap);
encoder.Frames.Add(frame);
using (FileStream stream = File.Create(fileName)) encoder.Save(stream);
}
但是当我将相同的逻辑应用到 UserControl 时
UserControl control = new UserControl(params)
// canvas.Children.Add(control); <-- if comment out, output blank/black image
control.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
control.Arrange(new Rect(0, 0, control.DesiredSize.Width, control.DesiredSize.Height));
foreach (CartesianChart cc in FindVisualChildren<CartesianChart>(control))
{
cc.Update(true, true); //force chart redraw
}
control.UpdateLayout();
SaveToPng(control, @"C:\Foo.png");
<!-- UserControl XAML -->
<UserControl>
<Grid>
<Border>
<Grid>
<Label></Label>
<Label></Label>
<Label></Label>
<CartesianChart DisableAnimations="True"></CartesianChart>
</Grid>
</Border>
</Grid>
</UserControl>
即输出 blank/black 图像。只有当我将 UserControl 添加到 window/XAML 上存在且可见的 UIControl 时,UserControl 才会正确呈现到图像(例如 canvas.Children.Add(lc)
)。然后我也尝试了 SO: How to render a WPF UserControl to a bitmap without creating a window 中描述的解决方案,但我得到了相同的结果 - 即我需要首先将此 UserControl 添加到可见的 UIControl,无论我是否在 UserControl 上执行 UpdateLayout
。
为什么第一个示例 (Canvas) 得到渲染,而不是第二个示例 (UserControl)?有什么区别,我该如何解决?
对我来说,这仅适用于图表以及整个用户控件:
(注意:确保您的用户控件具有可见的背景颜色,如果背景是透明的,它将呈现为透明,大多数图像查看器显示为黑色)
编辑:好的,我想如果图表不可见,我的解决方案将不起作用。但是如果你不能让它工作,为什么不在新的 window 中显示用户控件,保存它并再次关闭 window?
public static BitmapSource RenderChartAsImage(FrameworkElement chart)
{
RenderTargetBitmap image = new RenderTargetBitmap((int)chart.ActualWidth, (int)chart.ActualHeight,
96, 96, PixelFormats.Pbgra32);
image.Render(chart);
return image;
}
public static void SaveChartImage(FrameworkElement chart)
{
System.Windows.Media.Imaging.BitmapSource bitmap = RenderChartAsImage(chart);
Microsoft.Win32.SaveFileDialog saveDialog = new Microsoft.Win32.SaveFileDialog();
saveDialog.FileName += "mychart";
saveDialog.DefaultExt = ".png";
saveDialog.Filter = "Image (*.png)|*.png";
if (saveDialog.ShowDialog() == true)
{
using (FileStream stream = File.Create(saveDialog.FileName))
{
System.Windows.Media.Imaging.PngBitmapEncoder encoder = new System.Windows.Media.Imaging.PngBitmapEncoder();
encoder.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create(bitmap));
encoder.Save(stream);
}
}
}
我一直在渲染 window 中未显示的 UserControl 的 black/blank 图像。 UserControl 包含 LiveChart 的 CartesianChart 和一些 UIElement。首先我从 SO: C# chart to image with LiveCharts 借用解决方案
和 Github: Live-Charts/ChartToImageSample.xaml.cs 并在运行时生成的简单 UIControl 上应用 SaveToPng
和 EncodeVisual
(未在 window 中添加或显示),这有效。
Canvas control = new Canvas() { Width=100, Height=100, Background = new SolidColorBrush(Colors.Pink)};
control.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
control.Arrange(new Rect(0, 0, control.DesiredSize.Width, control.DesiredSize.Height));
control.UpdateLayout();
SaveToPng(control, @"C:\Foo.png");
private void SaveToPng(FrameworkElement visual, string fileName)
{
PngBitmapEncoder encoder = new PngBitmapEncoder();
EncodeVisual(visual, fileName, encoder);
}
private static void EncodeVisual(FrameworkElement visual, string fileName, BitmapEncoder encoder)
{
RenderTargetBitmap bitmap = new RenderTargetBitmap((int)visual.ActualWidth, (int)visual.ActualHeight, 96, 96, PixelFormats.Pbgra32);
bitmap.Render(visual);
BitmapFrame frame = BitmapFrame.Create(bitmap);
encoder.Frames.Add(frame);
using (FileStream stream = File.Create(fileName)) encoder.Save(stream);
}
但是当我将相同的逻辑应用到 UserControl 时
UserControl control = new UserControl(params)
// canvas.Children.Add(control); <-- if comment out, output blank/black image
control.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
control.Arrange(new Rect(0, 0, control.DesiredSize.Width, control.DesiredSize.Height));
foreach (CartesianChart cc in FindVisualChildren<CartesianChart>(control))
{
cc.Update(true, true); //force chart redraw
}
control.UpdateLayout();
SaveToPng(control, @"C:\Foo.png");
<!-- UserControl XAML -->
<UserControl>
<Grid>
<Border>
<Grid>
<Label></Label>
<Label></Label>
<Label></Label>
<CartesianChart DisableAnimations="True"></CartesianChart>
</Grid>
</Border>
</Grid>
</UserControl>
即输出 blank/black 图像。只有当我将 UserControl 添加到 window/XAML 上存在且可见的 UIControl 时,UserControl 才会正确呈现到图像(例如 canvas.Children.Add(lc)
)。然后我也尝试了 SO: How to render a WPF UserControl to a bitmap without creating a window 中描述的解决方案,但我得到了相同的结果 - 即我需要首先将此 UserControl 添加到可见的 UIControl,无论我是否在 UserControl 上执行 UpdateLayout
。
为什么第一个示例 (Canvas) 得到渲染,而不是第二个示例 (UserControl)?有什么区别,我该如何解决?
对我来说,这仅适用于图表以及整个用户控件: (注意:确保您的用户控件具有可见的背景颜色,如果背景是透明的,它将呈现为透明,大多数图像查看器显示为黑色)
编辑:好的,我想如果图表不可见,我的解决方案将不起作用。但是如果你不能让它工作,为什么不在新的 window 中显示用户控件,保存它并再次关闭 window?
public static BitmapSource RenderChartAsImage(FrameworkElement chart)
{
RenderTargetBitmap image = new RenderTargetBitmap((int)chart.ActualWidth, (int)chart.ActualHeight,
96, 96, PixelFormats.Pbgra32);
image.Render(chart);
return image;
}
public static void SaveChartImage(FrameworkElement chart)
{
System.Windows.Media.Imaging.BitmapSource bitmap = RenderChartAsImage(chart);
Microsoft.Win32.SaveFileDialog saveDialog = new Microsoft.Win32.SaveFileDialog();
saveDialog.FileName += "mychart";
saveDialog.DefaultExt = ".png";
saveDialog.Filter = "Image (*.png)|*.png";
if (saveDialog.ShowDialog() == true)
{
using (FileStream stream = File.Create(saveDialog.FileName))
{
System.Windows.Media.Imaging.PngBitmapEncoder encoder = new System.Windows.Media.Imaging.PngBitmapEncoder();
encoder.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create(bitmap));
encoder.Save(stream);
}
}
}