Преобразовать путь WPF в растровый файл - PullRequest
4 голосов
/ 07 марта 2012

Я хочу иметь возможность загружать ресурсный словарь WPF и выводить их один за другим в файлы (jpg, bmp, это не имеет значения). Это будет в библиотеке классов, к которой будет обращаться приложение MVC для рендеринга в поток http, поэтому я делаю это исключительно в коде (без страниц XAML).

Мне удалось загрузить словарь и выполнить итерации по путям, но когда я сохраняю изображения на диск, они остаются пустыми. Я знаю, что упускаю что-то тривиальное, например применение пути к фрагменту геометрии или добавление его в некоторый содержащий прямоугольник или что-то еще, но мой опыт работы с WPF несколько ограничен.

Я использую следующий код:

У меня есть словарь ресурсов WPF, содержащий несколько путей, например:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <Path x:Key="Path1" Data="M 100,200 C 100,25 400,350 400,175 H 280" Fill="White" Margin="10,10,10,10" Stretch="Fill"/>
  <Path x:Key="Path2" Data="M 10,50 L 200,70" Fill="White" Margin="10,10,10,10" Stretch="Fill"/>
</ResourceDictionary>

И класс для чтения и вывода файлов:

public class XamlRenderer
{
    public void RenderToDisk()
    {
        ResourceDictionary resource = null;

        Thread t = new Thread(delegate()
        {
            var s = new FileStream(@"C:\Temp\myfile.xaml", FileMode.Open);
            resource = (ResourceDictionary)XamlReader.Load(s);
            s.Close();

            foreach (var item in resource)
            {
                var resourceItem = (DictionaryEntry)item;
                var path = (System.Windows.Shapes.Path)resourceItem.Value;

                var panel = new StackPanel();

                var greenBrush = new SolidColorBrush {Color = Colors.Green};

                path.Stroke = Brushes.Blue;
                path.StrokeThickness = 2;
                path.Fill = greenBrush;

                panel.Children.Add(path);

                panel.UpdateLayout();

                string filepath = @"C:\Temp\Images\" + resourceItem.Key + ".jpg";

                SaveImage(panel, 64, 64, filepath);
            }
        });

        t.SetApartmentState(ApartmentState.STA);
        t.Start();
    }

    public void SaveImage(Visual visual, int width, int height, string filePath)
    {
        var bitmap =
            new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32);
        bitmap.Render(visual);

        var image = new PngBitmapEncoder();
        image.Frames.Add(BitmapFrame.Create(bitmap));
        using (Stream fs = File.Create(filePath))
        {
            image.Save(fs);
        }
    } 
}

1 Ответ

6 голосов
/ 08 марта 2012

После долгих поисков, проб и ошибок я, кажется, пришел к решению.Этот пост указал мне правильное направление.Было несколько проблем:

  • Теперь я устанавливал размер пути и контейнера
  • У контейнера панели стека есть некоторые нюансы, которые вызывали проблемы, поэтому я заменил его нахолст
  • Самое главное, Measure() и Arrange() должны быть вызваны для элемента контейнера.Вызов UpdateLayout() не требуется.

Как только эти проблемы были устранены, изображения отображаются на диск (хотя есть проблема с соотношением сторон, которую мне еще предстоит устранить).это обновленный код:

    public void RenderToDisk()
    {
        ResourceDictionary resource = null;

        Thread t = new Thread(delegate()
        {
            var s = new FileStream(@"C:\Temp\myfile.xaml", FileMode.Open);
            resource = (ResourceDictionary)XamlReader.Load(s);
            s.Close();

            foreach (var item in resource)
            {
                var resourceItem = (DictionaryEntry)item;
                var path = (System.Windows.Shapes.Path)resourceItem.Value;

                path.Margin = new Thickness(10);
                path.HorizontalAlignment = HorizontalAlignment.Center;
                path.VerticalAlignment = VerticalAlignment.Center;
                path.Width = 48;
                path.Height = 48;
                path.Stroke = Brushes.White;
                path.Fill = Brushes.Black;

                var canvas = new Canvas();
                canvas.Width = 64;
                canvas.Height = 64;
                canvas.Margin = new Thickness(0);
                canvas.Background = Brushes.Transparent;

                canvas.Children.Add(path);

                canvas.Measure(new Size(canvas.Width, canvas.Height));
                canvas.Arrange(new Rect(new Size(canvas.Width, canvas.Height)));

                string filepath = @"C:\Temp\Images\" + resourceItem.Key + ".png";

                SaveImage(canvas, (int)canvas.Width, (int)canvas.Height, filepath);
            }
        });

        t.SetApartmentState(ApartmentState.STA);
        t.Start();
    }
...