问题
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).
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.
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 ?
Double chart
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:
MyGraph = new GraphMaker();
MyGraph = GiveAGraph(MyGraph);
And the class "MakeReport" will complete the chart with some values with the sub-program "GiveAGraph()":
GraphData.SeriesCollection.Add(new RowSeries
{
Title = Criteria,
Values = DataValues,
ScalesYAt = Index,
DataLabels = true
});
End of "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.
The sub-program "GiveAnImageFromChart" included in the "GraphMaker" class is :
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).
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.
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.
PS: sorry for my english. Don't hesitate to correct me.
回答1:
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.
This is my GraphMaker.xaml file:
<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
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.
回答2:
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:
https://github.com/beto-rodriguez/Live-Charts/issues/243
Hope it helps
回答3:
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.
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);
}
来源:https://stackoverflow.com/questions/46932672/c-sharp-chart-to-image-with-livecharts