Сохранение изображения UIElement, визуализированного больше, чем кажется на экране
У меня есть диаграмма, которую я показываю пользователю, и я хочу иметь возможность экспортировать диаграмму в виде изображения на диск, чтобы они могли использовать ее вне приложения (для презентации или чего-то еще).
Мне удалось реализовать основную идею, используя PngBitmapEncoder и RenderTargetBitmap, но изображение, которое я извлекаю из него, является очень маленьким, чтобы его можно было реально использовать, и я хочу получить гораздо большее изображение.
Я попытался просто увеличить высоту и ширину элемента управления, который я хотел визуализировать, но родительский элемент, похоже, имеет прямой контроль над размером визуализации. Из этого я попытался продублировать UIElement в памяти, но затем размер рендеринга был (0,0), и когда я попытался использовать методы для его рендеринга, такие как Measure() Arrange() и UpdateLayout(), они выдают исключения о нужно разъединить родителя, чтобы вызвать их, но так как он находится в памяти и не отображается, не должно быть родителя?
Все это делается с помощью API построения графиков Visiblox
Вот то, что у меня есть сейчас, кроме того, что оно не работает:(
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);
Я стал немного ближе, теперь он отображает фон графика как ось и т. Д., Но не фактические линии, которые изображаются на графике. Ниже обновленный источник
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);
}
}
Итак, я получаю что-то вроде этого:
Который большой, но бесполезный, поскольку в нем ничего нет.
3 ответа
http://www.visiblox.com/blog/2011/05/printing-visiblox-charts
Главное, чего мне не хватало, было
InvalidationHandler.ForceImmediateInvalidate = true;
Установив это до того, как я отобразил график в памяти, а затем восстановил его, как только закончил. Оттуда было гладко: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);
}
Я думаю, что это может помочь:
Экспорт диаграммы Visifire Silverlight в виде изображения с помощью загружаемого решения Silverlight.