Saving a UIElement Image Displayed More Than On Screen

I have a chart that I show to the user, and I want to be able to export the chart as an image to disk so that they can use it outside the application (for presentation or something else).

I managed to get the main idea to work using PngBitmapEncoder and RenderTargetBitmap, but the image I get from it is small to really be useful, and I want to get a much larger image.

I tried just to increase the height and width of the control that I wanted to display, but the parent has direct control over the size of the rendering. From this, I tried to duplicate the UIElement in memory, but then the rendering size was (0,0), and when I tried to use methods for rendering it, such as Measure () Arrange () and UpdateLayout (), they throw exceptions from the need to separate the parent to call them, but since it is not displayed in memory, should the parent not be?

All this is done with the Visiblox Mapping API

Here is what I got at the moment, except that it does not work :(

var width = 1600; var height = 1200; var newChart = new Chart { Width = width, Height = height, Title = chart.Title, XAxis = chart.XAxis, YAxis = chart.YAxis, Series = chart.Series}; Debug.WriteLine(newChart.RenderSize); var size = new Size(width, height); newChart.Measure(size); newChart.Arrange(new Rect(size)); newChart.UpdateLayout(); Debug.WriteLine(newChart.RenderSize); var rtb = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32); rtb.Render(newChart); var encoder = new PngBitmapEncoder(); encoder.Frames.Add(BitmapFrame.Create(rtb)); using (var stream = fileDialog.OpenFile()) encoder.Save(stream); 

I came a little closer, now it displays the axis of the graph around the axis, etc., but not the actual lines that are drawn. Below is the updated source

 public static void RenderChartToImage(Chart elementToRender, string filename) { if (elementToRender == null) return; Debug.Write(elementToRender.RenderSize); var clone = new Chart(); clone.Width = clone.Height = double.NaN; clone.HorizontalAlignment = HorizontalAlignment.Stretch; clone.VerticalAlignment = VerticalAlignment.Stretch; clone.Margin = new Thickness(); clone.Title = elementToRender.Title; clone.XAxis = new DateTimeAxis(); clone.YAxis = new LinearAxis() { Range = Range<double>)elementToRender.YAxis.Range}; foreach (var series in elementToRender.Series) { var lineSeries = new LineSeries { LineStroke = (series as LineSeries).LineStroke, DataSeries = series.DataSeries }; clone.Series.Add(lineSeries); } var size = new Size(1600, 1200); clone.Measure(size); clone.Arrange(new Rect(size)); clone.UpdateLayout(); Debug.Write(clone.RenderSize); var height = (int)clone.ActualHeight; var width = (int)clone.ActualWidth; var renderer = new RenderTargetBitmap(width, height, 96d, 96d, PixelFormats.Pbgra32); renderer.Render(clone); var pngEncoder = new PngBitmapEncoder(); pngEncoder.Frames.Add(BitmapFrame.Create(renderer)); using (var file = File.Create(filename)) { pngEncoder.Save(file); } } 

So, I get something like this: chart

Which, while large, is not useful because it did not draw anything.

+6
source share
3 answers

http://www.visiblox.com/blog/2011/05/printing-visiblox-charts

The main thing that I was missing was

 InvalidationHandler.ForceImmediateInvalidate = true; 

Set this before I display the chart in memory and then return it as soon as I finish. From there was a smooth swim: D

+3
source
 RenderTargetBitmap DrawToImage<T>(T source, double scale) where T:FrameworkElement { var clone = Clone(source); clone.Width = clone.Height = Double.NaN; clone.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch; clone.VerticalAlignment = System.Windows.VerticalAlignment.Stretch; clone.Margin = new Thickness(); var size = new Size(source.ActualWidth * scale, source.ActualHeight * scale); clone.Measure(size); clone.Arrange(new Rect(size)); var renderBitmap = new RenderTargetBitmap((int)clone.ActualWidth, (int)clone.ActualHeight, 96, 96, PixelFormats.Pbgra32); renderBitmap.Render(clone); return renderBitmap; } static T Clone<T>(T source) where T:UIElement { if (source == null) return null; string xaml = XamlWriter.Save(source); var reader = new StringReader(xaml); var xmlReader = XmlTextReader.Create(reader, new XmlReaderSettings()); return (T)XamlReader.Load(xmlReader); } 
+2
source

Source: https://habr.com/ru/post/898116/


All Articles