开发者

Saving an image of a UIElement rendered larger than it appears on screen

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

I've managed to get the basic idea working using PngBitmapEncoder and RenderTargetBitmap but the image I get out of it is way to small to really be usable and I want to get a much larger image.

I tried to simply increase the Height and Width of the control I was wanting to render, but the parent seems to have direct control on the render size. From this I tried to duplicate the UIElement in memory but then the render size was (0,0) and when I tried to use methods to get it to render, such as Measure() Arrange() and UpdateLayout() they throw exceptions about needing to decouple the parent to call these, but as it's in memory and not rendered there shouldn't be a parent?

This is all done with Visiblox charting API

Here is what I've got currently, except it doesn't 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've gotten a bit closer, it now render the graph background the axis' etc. but just not the actual lines that are being graphed. Below is an 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 out something like this:

Saving an image of a UIElement rendered larger than it appears on screen

Which while big, isn't useful as it has nothing charted.


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

The main point I was missing was

InvalidationHandler.ForceImmediateInvalidate = true;

Setting this before I rendered the chart in memory and then reverting it once I had finished. From there it was smooth sailing :D


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);
}


I think these might help :

Exporting Visifire Silverlight Chart as Image with a downloadable silverlight solution.

Exporting Chart as Image in WPF

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜