I have a WPF application where I make an animation. I want to save this animation as an animated GIF. Building this GIF is a time consuming operation so I don't want to do it on the UI thread.
The basic code I use is like this.
private async void SaveAnimationAsGIF(string fileName)
{
const float frameRate = 25;
var rtb = new RenderTargetBitmap(
800, //width
400, //height
96, //dpi x
96, //dpi y
PixelFormats.Pbgra32 // pixelformat
);
AnimationRenderer renderer = new AnimationRenderer();
renderer.ViewportWidth = rtb.Width;
renderer.ViewportHeight = rtb.Height;
Grid grid = new Grid();
grid.Width = rtb.Width;
grid.Height = rtb.Width;
grid.Background = Brushes.White;
// Calculate the delay between the frames (in msec)
int delay = (int)(1000 / frameRate);
// Initialize the encoder
AnimatedGifEncoder e = new AnimatedGifEncoder();
e.Start(fileName);
e.SetFrameRate(frameRate);
for (double time = 0; time < 1; time += (double)delay / 1000) {
grid.Children.Clear();
renderer.CurrentTime = time;
Path strokePath = new Path();
strokePath.Data = renderer.StrokePath;
strokePath.Stroke = Brushes.Blue;
strokePath.StrokeThickness = 1.0;
grid.Children.Add(strokePath);
grid.Measure(new Size(rtb.Width, rtb.Height));
grid.Arrange(new Rect(0, 0, rtb.Width, rtb.Height));
rtb.Clear();
rtb.Render(grid);
await Task.Run(() => e.AddFrame(rtb));
}
e.Finish();
}
Removing the async/await and the Task.Run this works but on the UI thread. Using the code as shown here I get an exception "The calling thread cannot access this object because a different thread owns it." when executing the Task.Run
.
What am I doing wrong here
Edit: Changing the Task line to
RenderTargetBitmap rtb1 = rtb.GetAsFrozen() as RenderTargetBitmap;
await Task.Run(() => e.AddFrame(rtb1));
did the trick.