0

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.

  • "What am I doing wrong here?" You're accessing an object with thread affinity in a thread other than the one that it was created in. My guess is the RenderTargetBitmap in the Task action. You may try to `Freeze()` it. – Clemens Nov 21 '17 at 06:57
  • Yes, making rtb frozen got it to work. Thanks! – Joost Zalmstra Nov 21 '17 at 09:54

0 Answers0