wpf c# 使用 LiveCharts 将图表转换为图像
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/46932672/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
c# chart to image with LiveCharts
提问by Filotix
i have a little problem. I want to export to an image my charts. I known that is possible with the code given by beto-rodriguez (here).
我有一个小问题。我想将我的图表导出为图像。我知道使用 beto-rodriguez 给出的代码(这里)是可能的。
But i have a problem, i can't have what i could have by displaying it in the screen. See the image above. On the bottom right, i have the image saved in png. And in the left of the image, i have the chart with all the parameters displayed where i want.
但是我有一个问题,我不能通过在屏幕上显示它来获得我可以拥有的东西。请参阅上图。在右下角,我将图像保存为 png。在图像的左侧,我有一个图表,其中显示了我想要的所有参数。
Do you known if it's possible to have the same chart (in the left) in the saved image ? Actually, i use a thread to capture (copy/paste) the image automatically.
您知道是否可以在保存的图像中使用相同的图表(在左侧)?实际上,我使用线程自动捕获(复制/粘贴)图像。
Do you known what are the parameters i must set on to have the correct image ?
你知道我必须设置哪些参数才能获得正确的图像吗?
Thanks in advance. Regards.
提前致谢。问候。
********************************* After edit
************************************* 编辑后
Sorry for my late repsonse. I try what you said but unfornately I can't made that i want. I will explain what i do: I have a class "MakeReport" who can call another class "GraphMaker" with:
抱歉我迟到了。我尝试了你所说的但不幸的是我无法做到我想要的。我将解释我的工作:我有一个“MakeReport”类,它可以调用另一个类“GraphMaker”:
MyGraph = new GraphMaker();
MyGraph = GiveAGraph(MyGraph);
And the class "MakeReport" will complete the chart with some values with the sub-program "GiveAGraph()":
类“MakeReport”将使用子程序“GiveAGraph()”完成带有一些值的图表:
GraphData.SeriesCollection.Add(new RowSeries
{
Title = Criteria,
Values = DataValues,
ScalesYAt = Index,
DataLabels = true
});
End of "GiveAGRaph()".
“GiveAGraph()”结束。
Now I have a chart ready to display, i want to use it to make an image and for test (and debug) i show it:
现在我有一个图表可以显示,我想用它来制作图像并为了测试(和调试)我展示它:
// Chart to Image
MyGraph.GiveMeAnImageFromChart(); <-- to make a picture with the chart
// Show the graph
MyGraph.Show(); <-- for debug and test, i display it.
With "MyGraph.GiveAnImageFromChart()", i don't have the same result than "MyGraph.Show()". The picture (save as png) is different to the displayed chart.
使用“MyGraph.GiveAnImageFromChart()”,我得到的结果与“MyGraph.Show()”不同。图片(另存为png)与显示的图表不同。
The sub-program "GiveAnImageFromChart" included in the "GraphMaker" class is :
“GraphMaker”类中包含的子程序“GiveAnImageFromChart”是:
public void GiveMeAnImageFromChart()
{
var viewbox = new Viewbox();
myChart.Background = Brushes.White;
myChart.DataContext = this;
// myChart il faut tout mettre en paramètres
viewbox.Child = myChart;
viewbox.Measure(myChart.RenderSize);
viewbox.Arrange(new Rect(new Point(0, 0), myChart.RenderSize));
myChart.Update(true, true); //force chart redraw
viewbox.UpdateLayout();
SaveToPng(myChart, "chart.png");
//png file was created at the root directory.
}
The "myChart" variable is public. The "SaveToPng" program used come from your example (here).
“myChart”变量是公开的。使用的“SaveToPng”程序来自您的示例(此处)。
To save the picture, i try with the following method :
为了保存图片,我尝试使用以下方法:
public System.Drawing.Bitmap ControlToImage(Visual target, double dpiX, double dpiY)
{
if (target == null)
{
return null;
}
// render control content
Rect bounds = VisualTreeHelper.GetDescendantBounds(target);
Console.WriteLine("Bounds width = " + bounds.Width + " et bounds height = " + bounds.Height);
RenderTargetBitmap rtb = new RenderTargetBitmap((int)(bounds.Width * dpiX / 96.0),
(int)(bounds.Height * dpiY / 96.0),
dpiX,
dpiY,
PixelFormats.Pbgra32);
DrawingVisual dv = new DrawingVisual();
using (DrawingContext ctx = dv.RenderOpen())
{
VisualBrush vb = new VisualBrush(target);
ctx.DrawRectangle(vb, null, new Rect(new System.Windows.Point(), bounds.Size));
}
rtb.Render(dv);
//convert image format
MemoryStream stream = new MemoryStream();
BitmapEncoder encoder = new BmpBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(rtb));
encoder.Save(stream);
return new System.Drawing.Bitmap(stream);
}
With :
和 :
Bitmap ImageChart = MyGraph.ControlToImage(MyGraph, MyGraph.Width, MyGraph.Height);
With this method, i have an error because the "bounds.Width" and "bounds.Height" are equal to -8. And finally, i don't have any chart to convert.
使用这种方法,我有一个错误,因为“bounds.Width”和“bounds.Height”等于-8。最后,我没有任何要转换的图表。
I think i give a wrong "visual Target" in the "ControlImage" and I miss something but i don't know what. If you need more information, ask me. Thanks in advance for your help.
我想我在“ControlImage”中给出了错误的“视觉目标”,我错过了一些东西,但我不知道是什么。如果您需要更多信息,请询问我。在此先感谢您的帮助。
PS: sorry for my english. Don't hesitate to correct me.
PS:对不起我的英语。不要犹豫纠正我。
采纳答案by Filotix
thanks to bto-rdz, i made a solution. I found that i didn't use Livecharts correctly. So i post my code if someone need it.
感谢 bto-rdz,我做了一个解决方案。我发现我没有正确使用 Livecharts。所以如果有人需要,我会发布我的代码。
This is my GraphMaker.xaml file:
这是我的 GraphMaker.xaml 文件:
<UserControl x:Class="MyProject.GraphMaker"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MyProject"
mc:Ignorable="d"
d:DesignHeight="730" d:DesignWidth="1660">
<Grid>
</Grid>
</UserControl>
And my GraphMaker.xaml.cs file
还有我的 GraphMaker.xaml.cs 文件
using System;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using LiveCharts;
using LiveCharts.Wpf;
using System.Collections.Generic;
using System.ComponentModel;
namespace MyProject
{
public partial class GraphMaker : UserControl
{
// PUBLIC
public CartesianChart MyTestChart;
public SeriesCollection MySeriesCollection { get; set; }
public string[] Labels { get; set; }
public string AxisTitle { get; set; }
public Func<double, string> YFormatter { get; set; }
public Axis Axis1, Axis2, Axis3, Axis4, Axis5, Axis6, Axis7, Axis8, Axis9, Axis10, AxisXChart;
public GraphMaker()
{
InitializeComponent();
MySeriesCollection = new SeriesCollection();
MyTestChart = new CartesianChart
{
DisableAnimations = true,
Width = 1600,
Height = 700,
Series = MySeriesCollection
};
MyTestChart.LegendLocation = LegendLocation.Right;
// *** Axis 1 ***
Axis1 = new Axis();
Axis1.Foreground = Brushes.DodgerBlue;
Axis1.Position = AxisPosition.RightTop;
YFormatter = value => value.ToString("N2");
Axis1.LabelFormatter = YFormatter;
MyTestChart.AxisY.Add(Axis1);
// *** Axis 2 ***
Axis2 = new Axis();
Axis2.Foreground = Brushes.IndianRed;
Axis2.Position = AxisPosition.RightTop;
YFormatter = value => value.ToString("N2");
Axis2.LabelFormatter = YFormatter;
//MyTestChart.AxisY.Add(Axis2);
// *** Axis 3 ***
Axis3 = new Axis();
Axis3.Foreground = Brushes.Gold;
Axis3.Position = AxisPosition.RightTop;
YFormatter = value => value.ToString("N2");
Axis3.LabelFormatter = YFormatter;
//MyTestChart.AxisY.Add(Axis3);
// *** Axis 4 ***
Axis4 = new Axis();
Axis4.Foreground = Brushes.Gray;
Axis4.Position = AxisPosition.RightTop;
YFormatter = value => value.ToString("N2");
Axis4.LabelFormatter = YFormatter;
//MyTestChart.AxisY.Add(Axis4);
// *** Axis 5 ***
Axis5 = new Axis();
Axis5.Foreground = Brushes.DeepSkyBlue;
Axis5.Position = AxisPosition.RightTop;
YFormatter = value => value.ToString("N2");
Axis5.LabelFormatter = YFormatter;
//MyTestChart.AxisY.Add(Axis5);
// *** Axis 6 ***
Axis6 = new Axis();
Axis6.Foreground = Brushes.HotPink;
Axis6.Position = AxisPosition.RightTop;
YFormatter = value => value.ToString("N2");
Axis6.LabelFormatter = YFormatter;
//MyTestChart.AxisY.Add(Axis6);
// *** Axis 7 ***
Axis7 = new Axis();
Axis7.Foreground = Brushes.Orange;
Axis7.Position = AxisPosition.RightTop;
YFormatter = value => value.ToString("N2");
Axis7.LabelFormatter = YFormatter;
//MyTestChart.AxisY.Add(Axis7);
// *** Axis 8 ***
Axis8 = new Axis();
Axis8.Foreground = Brushes.RoyalBlue;
Axis8.Position = AxisPosition.RightTop;
YFormatter = value => value.ToString("N2");
Axis8.LabelFormatter = YFormatter;
//MyTestChart.AxisY.Add(Axis8);
// *** Axis 9 ***
Axis9 = new Axis();
Axis9.Foreground = Brushes.Black;
Axis9.Position = AxisPosition.RightTop;
Axis9.LabelFormatter = YFormatter;
//MyTestChart.AxisY.Add(Axis9);
// *** Axis 10 ***
Axis10 = new Axis();
Axis10.Foreground = Brushes.DarkTurquoise;
Axis10.Position = AxisPosition.RightTop;
YFormatter = value => value.ToString("N2");
Axis10.LabelFormatter = YFormatter;
//MyTestChart.AxisY.Add(Axis10);
AxisXChart = new Axis();
AxisXChart.Title = AxisTitle;
AxisXChart.Labels = Labels;
}
public void TakeTheChart()
{
var viewbox = new Viewbox();
viewbox.Child = MyTestChart;
viewbox.Measure(MyTestChart.RenderSize);
viewbox.Arrange(new Rect(new Point(0, 0), MyTestChart.RenderSize));
MyTestChart.Update(true, true); //force chart redraw
viewbox.UpdateLayout();
SaveToPng(MyTestChart, "Chart.png");
//png file was created at the root directory.
}
public void SaveToPng(FrameworkElement visual, string fileName)
{
var encoder = new PngBitmapEncoder();
EncodeVisual(visual, fileName, encoder);
}
private static void EncodeVisual(FrameworkElement visual, string fileName, BitmapEncoder encoder)
{
var bitmap = new RenderTargetBitmap((int)visual.ActualWidth, (int)visual.ActualHeight, 96, 96, PixelFormats.Pbgra32);
bitmap.Render(visual);
var frame = BitmapFrame.Create(bitmap);
encoder.Frames.Add(frame);
using (var stream = File.Create(fileName)) encoder.Save(stream);
}
}
}
Hope to help you.
希望能帮到你。
Have a nice day. Bye.
祝你今天过得愉快。再见。
回答by bto.rdz
The sample you pointed, is created a new chart instance in memory, that is why you are getting a different image, you could, reproduce the same properties in both charts, the one presented in the UI, and the one you are creating in memory, or you could just print the the current instance in the UI, as explained in this issue:
您指向的示例在内存中创建了一个新的图表实例,这就是为什么您获得不同的图像,您可以在两个图表中重现相同的属性,在 UI 中显示的一个,以及您在内存中创建的一个,或者您可以只在 UI 中打印当前实例,如本期所述:
https://github.com/beto-rodriguez/Live-Charts/issues/243
https://github.com/beto-rodriguez/Live-Charts/issues/243
Hope it helps
希望能帮助到你
回答by Can DOGRU
I have wrote extension method to save as image from cartesian chart for windows form. It can be edit your own way to get best one.
我已经编写了扩展方法来从 Windows 窗体的笛卡尔图中保存为图像。它可以编辑你自己的方式来获得最好的。
public static bool ChartToImage(this LiveCharts.WinForms.CartesianChart cartesianChart, LineSeries data, Axis AxisX, Axis AxisY,double Width, double Height, string fileName, string targetPath, out string locationOfImage, out Exception returnEx)
{
bool status = false;
returnEx = null;
locationPath = null;
try
{
var myChart = new LiveCharts.Wpf.CartesianChart
{
DisableAnimations = true,
Width = Width,
Height = Height,
Series = new SeriesCollection(cartesianChart.Series.Configuration)
{
new LineSeries
{
Title = data.Title,
LineSmoothness = data.LineSmoothness,
StrokeThickness = data.StrokeThickness,
PointGeometrySize = data.PointGeometrySize,
Stroke = data.Stroke,
Values=data.Values
}
}
};
myChart.AxisX.Add(new Axis { IsMerged = AxisX.IsMerged, FontSize = AxisX.FontSize, FontWeight = AxisX.FontWeight, Foreground = AxisX.Foreground, Separator = new LiveCharts.Wpf.Separator { Step = AxisX.Separator.Step, StrokeThickness = AxisX.Separator.StrokeThickness, StrokeDashArray = AxisX.Separator.StrokeDashArray, Stroke = AxisX.Separator.Stroke }, Title = AxisX.Title, MinValue = AxisX.MinValue, MaxValue = AxisX.MaxValue });
myChart.AxisY.Add(new Axis { IsMerged = AxisY.IsMerged, FontSize = AxisY.FontSize, FontWeight = AxisY.FontWeight, Foreground = AxisY.Foreground, Separator = new LiveCharts.Wpf.Separator { Step = AxisY.Separator.Step, StrokeThickness = AxisY.Separator.StrokeThickness, StrokeDashArray = AxisY.Separator.StrokeDashArray, Stroke = AxisX.Separator.Stroke }, Title = AxisY.Title, MinValue = AxisY.MinValue, MaxValue = AxisY.MaxValue });
var viewbox = new Viewbox();
viewbox.Child = myChart;
viewbox.Measure(myChart.RenderSize);
viewbox.Arrange(new Rect(new System.Windows.Point(0, 0), myChart.RenderSize));
myChart.Update(true, true); //force chart redraw
viewbox.UpdateLayout();
var encoder = new PngBitmapEncoder();
var bitmap = new RenderTargetBitmap((int)myChart.ActualWidth, (int)myChart.ActualHeight, 96, 96, PixelFormats.Pbgra32);
bitmap.Render(myChart);
var frame = BitmapFrame.Create(bitmap);
encoder.Frames.Add(frame);
string path = Path.Combine(targetPath, fileName);
using (var stream = File.Create(path))
{
encoder.Save(stream);
locationPath = path;
}
myChart = null;
viewbox = null;
encoder = null;
bitmap = null;
frame = null;
status = true;
}
catch (Exception ex)
{
returnEx = ex;
status = false;
}
return status;
}
On your main program :
在你的主程序上:
if(cartesianChart1.ChartToImage(data,axisX,axisY,600,200,"test.png", locationImage, out string locationOfFile, out Exception returnEx))
{
System.Windows.Forms.MessageBox.Show(locationOfFile);
}

