Convert WPF Path to Bitmap File

I want to be able to load WPF Resource Dictionary of Paths and output them one by one to files (jpg, bmp, it doesn't matter). This will be in the class library that the MVC application will access to render the HTTP stream, so I am doing this entirely inside the code (no XAML pages).

I was able to load the dictionary and iterate over the paths, but when I save the images to disk, they are empty. I know I am missing something trivial like applying a path to a piece of geometry or adding it to some kind of containing rectangle or something, but my WPF experience is somewhat limited.

I am using the following code:

I have a WPF resource dictionary containing multiple paths, for example:

<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>

      

And a class for reading and outputting files:

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

      

+3


source to share


1 answer


After much googling, trial and error, it looks like I've come to a solution. This post pointed me in the right direction. There were several problems:

  • Now I have set the path size and container
  • The stack panel container has some nuances causing problems, so I replaced it with canvas
  • The most important thing Measure()

    , and Arrange()

    you need to call in the container element. UpdateLayout()

    No call required.

After fixing these issues, images captured to disk (although I haven't fixed the aspect ratio issue yet).



Here's the updated code:

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

      

+6


source







All Articles