I tried to save chart as image as shown in below code,got error "The parameter value must be greater than zero.Parameter name: pixelWidth". Here my requrement is , Generating chart programatically and saving the same to JPEG in specified folder path. Anyone help me in doing this?
SeriesMapping sm1 = new SeriesMapping();
sm1.SeriesDefinition = new LineSeriesDefinition();
sm1.LegendLabel = "Line Series 1";
sm1.CollectionIndex = 0;
ItemMapping im1 = new ItemMapping();
im1.DataPointMember = DataPointMember.YValue;
sm1.ItemMappings.Add(im1);
SeriesMapping sm2 = new SeriesMapping();
sm2.SeriesDefinition = new LineSeriesDefinition();
sm2.LegendLabel = "Line Series 2";
sm2.CollectionIndex = 1;
ItemMapping im2 = new ItemMapping();
im2.DataPointMember = DataPointMember.YValue;
sm2.ItemMappings.Add(im2);
var itemsSource = new List<double>[] { new List<double> { 22, 12, 66, 76 }, new List<double> { 76, 45, 53, 43 } };
this.RadChart1.SeriesMappings.Add(sm1);
this.RadChart1.SeriesMappings.Add(sm2);
this.RadChart1.ItemsSource = itemsSource;
RadChart1.ExportToImage(
@"d:\remove\abc.png");
grid.Children.Add(RadChart1);
I tried to change ExportToImage method as follows, but there is no class named 'PngBitmapEncoder' under "Telerik.Windows.Media.Imaging" namespace in WPF related DLLs provided by Telerik, but this is working fine in Silverlight related DLLs provided by Telerik. Can anyone help me here to save chat as image in JPEG format.
Stream fileStream = File.Create(@"d:\ss\ss.png") ;
RadChart1.ExportToImage(fileStream, new Telerik.Windows.Media.Imaging.PngBitmapEncoder());
fileStream.Close();
31 Answers, 1 is accepted
Unfortunately currently it is not possible to export RadChart directly from code.Our developers are working on this issue and will provide support for it in one of the future versions of the control, but we cannot commit a concrete timeframe for its implementation.
Meanwhile, the easiest work-around would be creating a export button, similarly to the Export example in our demo .
Greetings,
Nikolay
the Telerik team
The ExportToImage method eventually calls into the method
GetBitmapSource(
FrameworkElement element, double dpiX, double dpiY)
This method is found in Telerik.Windows.Media.Image.ExportHelper (Controls_WPF project, ExportExtensions folder, ExportHelper.cs)
The first line of this method calls GetImageSize, which simply uses the element's ActualWidth and ActualHeight. These two are zero when the element is not rendered on the screen.
I modified the code to use element.Width and Height (and set them programatically in my project). This eliminates the error, and gets a lot closer to working. But the actual chart doesn't render - the resulting image is just the legend and the plot area is empty. It's like it's not allowing the chart to actually render.
I have a borderless form, sized 0x0. This form has the chart on it (just not visible because the form is too small.)
This form has a method to export the chart.
I can show this form, call the export method, then close the form from elsewhere in my code. Of course, I need to be able to show forms, something your specific situation may not support.
The trick to avoid the empty chart problem is to turn off animation:
chart.DefaultView.ChartArea.EnableAnimations = false;
(Note: I'm using the July 14 WPF release, not on the Aug 12 yet.)
So here is our solution using approach given in Converting and customizing XAML to PNG with server-side WPF
public
class
XamlToPngConverter
{
public
void
Convert(
double
width,
double
height,
Stream pngOutput)
{
// Round width and height to simplify
width = Math.Round(width);
height = Math.Round(height);
Thread pngCreationThread =
new
Thread(
delegate
()
{
RadChart chart = GetChart(width, height);
chart.Measure(
new
Size(width, height));
DrawingVisual visual =
new
DrawingVisual();
using
(visual.RenderOpen())
{
new
VisualBrush(chart);
}
try
{
chart.UpdateLayout();
chart.ExportToImage(pngOutput,
new
PngBitmapEncoder());
}
catch
(ObjectDisposedException)
{
// IF the operation lasted too long, the object might be disposed already
}
});
pngCreationThread.IsBackground =
true
;
pngCreationThread.SetApartmentState(ApartmentState.STA);
pngCreationThread.Start();
pngCreationThread.Join();
try
{
if
(pngOutput.Length == 0)
{
throw
new
TimeoutException();
}
}
catch
(ObjectDisposedException)
{
// If the object was disposed, it means that the Stream is ready.
}
}
private
RadChart GetChart(
double
width,
double
height)
{
RadChart chart =
new
RadChart();
SeriesMapping seriesMapping =
new
SeriesMapping();
seriesMapping.LegendLabel =
"Product Sales"
;
seriesMapping.SeriesDefinition =
new
LineSeriesDefinition();
seriesMapping.ItemMappings.Add(
new
ItemMapping(
"Month"
, DataPointMember.XValue));
seriesMapping.ItemMappings.Add(
new
ItemMapping(
"Quantity"
, DataPointMember.YValue));
chart.SeriesMappings.Add(seriesMapping);
chart.ItemsSource = CreateData();
chart.DefaultView.ChartArea.EnableAnimations =
false
;
chart.Width = width;
chart.Height = height;
return
chart;
}
private
List<ProductSales> CreateData()
{
List<ProductSales> persons =
new
List<ProductSales>();
persons.Add(
new
ProductSales(154, 1,
"January"
));
persons.Add(
new
ProductSales(138, 2,
"February"
));
persons.Add(
new
ProductSales(143, 3,
"March"
));
persons.Add(
new
ProductSales(120, 4,
"April"
));
persons.Add(
new
ProductSales(135, 5,
"May"
));
persons.Add(
new
ProductSales(125, 6,
"June"
));
persons.Add(
new
ProductSales(179, 7,
"July"
));
persons.Add(
new
ProductSales(170, 8,
"August"
));
persons.Add(
new
ProductSales(198, 9,
"September"
));
persons.Add(
new
ProductSales(187, 10,
"October"
));
persons.Add(
new
ProductSales(193, 11,
"November"
));
persons.Add(
new
ProductSales(212, 12,
"December"
));
return
persons;
}
}
Here you can get line chart as png on server-side.
But when you change seriesdefinition to BarSeriesDefinition you will get chart without bars. And trick with animation won't help.
Any ideas, what could be done to get bars shown in chart.
PS: Same problem with Pie chart.
Thanks, Alexey.
Indeed, there seems to be a problem exporting some series using this approach. Our developers would need a bit more time to investigate the issue and provide a resolution. We'll update you when there is sufficient progress.
Greetings,
Nikolay
the Telerik team
Thanks, Alexey.
Unfortunately, we cannot provide a work-around for the time being but our developers are on the task and you can expect a fix available for our official 2010.Q3 release, scheduled for mid November.
Greetings,
Nikolay
the Telerik team
Thanks for replay, be waiting for Q3 :)
Alexey
Now that Q3 release is out can you confirm that this has been fixed? I am using Silverlight, and am still experiencing problems with exporting series other than lines (using the Q3 2010 release).
Many thanks,
Chris
In order to export all chart series in SL, exporting has to be called within Dispatcher.BeginInvoke(..) and also calling Flush() on the stream.
Please, consider the following code snippet :
private void Button_Click(object sender, RoutedEventArgs e)
{
this.InitializeChart();
Dispatcher.BeginInvoke((Action)(() =>
{
ExportChart();
}));
}
private void InitializeChart()
{
int[] dataArray = new int[] { 12, 56, 23, 89, 12, 56, 34, 78, 32, 56 };
RadChart1.DefaultView.ChartArea.EnableAnimations = false;
RadChart1.ItemsSource = dataArray;
RadChart1.Rebind();
RadChart1.UpdateLayout();
}
private void ExportChart()
{
MemoryStream img = new MemoryStream();
RadChart1.ExportToImage(img, new PngBitmapEncoder());
img.Flush();
BitmapImage b = new BitmapImage();
b.SetSource(img);
image1.Source = b;
}
Best wishes,
Nikolay
the Telerik team
Got last bits from internal release, all I got is bar labels.
I think that bar have somewhere animation delay.
In example you provided, you have button click event. I think you were using Silverlight client application.
If yes, then this example won't help me, since I am trying to get screen shot on server-side using WPF chart.
Any ideas, how we can get around?
Thanks, Alexey.
This became really big issue for us. We must be able to convert the charts into images on the server side.
Please resolve this problem as soon as possible...
Thanks!
Alex.
Please, find attached a sample project demonstrating how to achieve this behavior. Currently the best work-around we've come to is by having the chart in a collapsed canvas, this way it is not displayed but can be exported correctly. Give it a try and let us know if it works on your side as well.
All the best,
Nikolay
the Telerik team
at System.Windows.Threading.Dispatcher.VerifyAccess()
at System.Windows.Threading.DispatcherObject.VerifyAccess()
at System.Windows.Application.get_MainWindow()
at Telerik.Windows.Controls.RadSlider..ctor()
at System.Xaml.Schema.XamlTypeInvoker.DefaultCtorXamlActivator.InvokeDelegate(Action`1 action, Object argument)
at System.Xaml.Schema.XamlTypeInvoker.DefaultCtorXamlActivator.CallCtorDelegate(XamlTypeInvoker type)
at System.Xaml.Schema.XamlTypeInvoker.DefaultCtorXamlActivator.CreateInstance(XamlTypeInvoker type)
at System.Xaml.Schema.XamlTypeInvoker.CreateInstance(Object[] arguments)
at MS.Internal.Xaml.Runtime.ClrObjectRuntime.CreateInstanceWithCtor(XamlType xamlType, Object[] args)
at MS.Internal.Xaml.Runtime.ClrObjectRuntime.CreateInstance(XamlType xamlType, Object[] args)
Could you, please, open a support ticket and send us a small sample application, as we haven't been able to reproduce a similar scenario with an error when exporting chart with a slider.
Kind regards,
Nikolay
the Telerik team
just checking there hasnt been an update to this for wpf that supports creating the image purely from code (not using your suggested display in hidden canvas hack). I need to create a service that can produce the image to any kind of client (wpf or other)
In order to export an image directly from code, please, consider doing it through a Dispatcher.BeginInvoke call in the following manner :
string imageName = "image.png";
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
ExportChart();
}
public void ExportChart()
{
Dispatcher.BeginInvoke((Action)(() => { ExportChart(); }), DispatcherPriority.Background);
RadChart1.Save(imageName, 128, 128, new PngBitmapEncoder());
}
Hope this would be helpful for you.
Best wishes,
Nikolay
the Telerik team
Just in case someone needs a solution to this, I've managed to get it working using the 2011 Q1 SP1 WPF Chart control.
RadChart chart =
new
RadChart();
chart.BeginInit();
chart.Width = 450;
chart.Height = 300;
chart.DefaultView.ChartArea.EnableAnimations =
false
;
SeriesMapping seriesMapping =
new
SeriesMapping();
seriesMapping.SeriesDefinition =
new
PieSeriesDefinition();
seriesMapping.SeriesDefinition.ItemLabelFormat =
"#%{p0}"
;
ItemMapping yMapping =
new
ItemMapping(
"<<Your field name>>"
, DataPointMember.YValue);
ItemMapping legendMapping =
new
ItemMapping(
"<<Your field name>>"
, DataPointMember.LegendLabel);
seriesMapping.ItemMappings.Add(yMapping);
seriesMapping.ItemMappings.Add(legendMapping);
chart.SeriesMappings.Add(seriesMapping);
// Force chart to measure itseft so it provides the actual width and height to export
chart.Measure(
new
System.Windows.Size(chart
.Width, chart
.Height));
chart.Arrange(
new
System.Windows.Rect(chart
.DesiredSize));
chart.EndInit();
chart.ItemsSource =
"<<Your datasource>>"
;
using
(MemoryStream ms =
new
MemoryStream())
{
chart.ExportToImage(ms);
// Do something with the memory stream
}
Has anybody got any suggestions? I really need to get this working. Code snippet below.
thanks,
Mike
class
ChartImageGenerator
{
public
void
GetChartImage()
{
byte
[] imageBytes;
var chart =
new
RadChart();
chart.BeginInit();
chart.Width = 600;
chart.Height = 450;
chart.DefaultView.ChartArea.EnableAnimations =
false
;
var seriesMapping =
new
SeriesMapping();
seriesMapping.ItemMappings.Add(
new
ItemMapping(
"X"
, DataPointMember.XValue));
seriesMapping.ItemMappings.Add(
new
ItemMapping(
"Y"
, DataPointMember.YValue));
seriesMapping.ItemMappings.Add(
new
ItemMapping(
"Label"
, DataPointMember.Label));
chart.SeriesMappings.Add(seriesMapping);
chart.DefaultSeriesDefinition =
new
ScatterSeriesDefinition()
{
LabelSettings =
new
LabelSettings() { Distance = 20, ShowConnectors =
true
},
LegendDisplayMode = LegendDisplayMode.None,
};
chart.DefaultView.ChartArea.AxisX.AutoRange =
false
;
chart.DefaultView.ChartArea.AxisX.MinValue = 0.0;
chart.DefaultView.ChartArea.AxisX.MaxValue = 600.0;
chart.DefaultView.ChartArea.AxisY.AutoRange =
false
;
chart.DefaultView.ChartArea.AxisY.MinValue = 0.0;
chart.DefaultView.ChartArea.AxisY.MaxValue = 450.0;
chart.DefaultView.ChartArea.Height = 450;
chart.DefaultView.ChartArea.Width = 600;
chart.DefaultView.ChartArea.SmartLabelsEnabled =
true
;
chart.DefaultSeriesDefinition.ShowItemLabels =
true
;
// Only show the chart area
chart.DefaultView.ChartTitle.Visibility = Visibility.Collapsed;
chart.DefaultView.ChartLegend.Visibility = Visibility.Collapsed;
chart.DefaultView.ChartArea.AxisX.Visibility = Visibility.Collapsed;
chart.DefaultView.ChartArea.AxisY.Visibility = Visibility.Collapsed;
// Force chart to measure itseft so it provides the actual width and height to export
chart.Measure(
new
System.Windows.Size(chart.Width, chart.Height));
chart.Arrange(
new
System.Windows.Rect(chart.DesiredSize));
chart.EndInit();
chart.ItemsSource = GetDataItems();
//test export image directly to file
chart.ExportToImage(@
"c:\temp\chartImage1.png"
);
// test export image to memory stream
using
(var ms =
new
MemoryStream())
{
chart.ExportToImage(ms);
ms.Flush();
imageBytes = ms.ToArray();
}
var fs =
new
FileStream(@
"c:\temp\chartimage2.png"
, FileMode.Create, FileAccess.ReadWrite);
var bw =
new
BinaryWriter(fs);
bw.Write(imageBytes);
bw.Close();
}
private
static
List<UserDataPoint> GetDataItems()
{
var series =
new
List<UserDataPoint>
{
new
UserDataPoint {Label =
"SA1"
, X = 300.0, Y = 200.0},
new
UserDataPoint {Label =
"SA2"
, X = 300.0, Y = 200.0},
new
UserDataPoint {Label =
"SA3"
, X = 300.0, Y = 200.0},
new
UserDataPoint {Label =
"SA4"
, X = 300.0, Y = 410.0},
new
UserDataPoint {Label =
"SA5"
, X = 300.0, Y = 405.0},
new
UserDataPoint {Label =
"SA6"
, X = 300.0, Y = 400.0},
new
UserDataPoint {Label =
"SA7"
, X = 300.0, Y = 450.0},
};
return
series;
}
}
public class UserDataPoint {
public
UserDataPoint(
double
x,
double
y)
{
this
.X = x;
this
.Y = y;
}
public
UserDataPoint(
double
high,
double
low,
double
open,
double
close)
{
this
.High = high;
this
.Low = low;
this
.Open = open;
this
.Close = close;
}
public
double
X {
get
;
set
; }
public
double
Y {
get
;
set
; }
public
double
High {
get
;
set
; }
public
double
Low {
get
;
set
; }
public
double
Open {
get
;
set
; }
public
double
Close {
get
;
set
; }
public
double
BubbleSize {
get
;
set
; }
public
string
LegendLabel {
get
;
set
; }
public
string
Label {
get
;
set
; }
}
}
Could you , please, try filling the chart with data first before calling Measure/Arrange. Perhaps this approach would help displaying the connectors as well.
Greetings,
Nikolay
the Telerik team
No, filling the chart with data before the measure and arrange calls gave me the same result with no connector lines showing.
Mike
I have forwarded this issue to our developers for further review. You can expect a fix in one of the future versions of the control. Please, excuse us for the inconvenience caused.
Best wishes,
Nikolay
the Telerik team
We are currently evaluating several vendors for the chart and gauge controls and detected (using the Q2 2011 WPF controls) the same issue (barseries not drawn inside exported chart image) as mentioned in this thread. It is important for us that we can generate this image from code in one run on serverside. Currently we have implemented a wrapper library containing wpf usercontrols using databinding to generate images for charts and gauges that are transfered to our clients.
We tried all tips and tricks mentioned inside this thread. The answer you posted to brian on May 2, 2011 partly delivered a solution because it was eventually (after 12 Radchart1.save runs) able to supply an image with all chartseries (including the barseries).
However, are there other scenario's that allow us to generate the image (with all chartseries) in 1 run?
Lineseries are drawn properly on the first run and we disabled the animations, so why aren't barseries drawn the same way? What is causing this difference in drawing?
thanks,
Ordwin
We are currently evaluating several vendors for the chart and gauge controls and detected (using the Q2 2011 WPF controls) the same issue (barseries not drawn inside exported chart image) as mentioned in this thread. It is important for us that we can generate this image from code in one run on serverside. Currently we have implemented a wrapper library containing wpf usercontrols using databinding to generate images for charts and gauges that are transfered to our clients.
We tried all tips and tricks mentioned inside this thread. The answer you posted to brian on May 2, 2011 partly delivered a solution because it was eventually (after 12 Radchart1.save runs) able to supply an image with all chartseries (including the barseries).
However, are there other scenario's that allow us to generate the image (with all chartseries) in 1 run?
Lineseries are drawn properly on the first run and we disabled the animations, so why aren't barseries drawn the same way? What is causing this difference in drawing?
thanks,
Ordwin
This is a note to let you know we are processing the support ticket you have sent and our developers are investigating the attached project, so we will get back to you with any findings.
Regards,
Nikolay
the Telerik team
Could you, please, open a support ticket and send us a sample application which reproduces the exporting issue you've encountered, so that our developers can have a look at it and provide a solution.
All the best,
Nikolay
the Telerik team
I will prepare a project to demonstrate the issue and open a support ticket. In the interim, what I have done, as a rather kludgey and distasteful work around, is to add a load event handler (excuse me if that is not the correct jargon, I am.a net newbie ) that actual opens a window. Once the chart is rendered to the screen my png files a output perfectly. I would perfer not to have to have continuous flashes to a monitor to do this. If it is unavoidable, I suppose I could put up a GUI to display the processing activity of the service including the graphs being generated. Not an entirely unreasonable approach.
private void Window_Loaded(object sender, RoutedEventArgs e)
{
byte[] imageBytes;
var enc = new System.Windows.Media.Imaging.PngBitmapEncoder();
using (var ms = new MemoryStream())
{
telerikChart.ExportToImage(ms, enc);
ms.Flush();
imageBytes = ms.ToArray();
}
var fs = new FileStream(@"p:\ICRFS-Plus\test.png", FileMode.Create, FileAccess.ReadWrite);
var bw = new BinaryWriter(fs);
bw.Write(imageBytes);
bw.Close();
this.Close();
}
This is a quick follow-up to inform you that the Support ticket you have sent us has been handled. Let's continue the discussion there to prevent a duplication of efforts.
In short, the issue was caused by the framework specifics regarding the layout. Because the chart is not attached to the visual tree - you need to manually call the measure and arrange pass.
Yavor
the Telerik team