public static async IAsyncEnumerable<Frame> Slide(this IAsyncEnumerable<Frame> frames,
int directionHorizontal = 1, int directionVertical = 0,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
const int minMoves = 10;
var allFrames = await frames.ToListAsync(cancellationToken);
// padding to more than `minMoves` frames when not enough
var targetFrames = allFrames.Count;
var loopTimes = (minMoves + targetFrames - 1) / targetFrames;
targetFrames = loopTimes * targetFrames;
var finalFrames = allFrames.Loop(loopTimes - 1).ToList();
for (var i = 0; i < finalFrames.Count; i++)
{
using var frame = finalFrames[i];
Image newFrame = new Image<Rgba32>(frame.Image.Size.Width, frame.Image.Size.Height);
newFrame.Mutate(ProcessSlide(i, frame.Image));
yield return new Frame() { Sequence = i, Image = newFrame };
}
yield break;
Action<IImageProcessingContext> ProcessSlide(int i, Image image)
{
return ctx =>
{
var x = Math.Round((1f * i / finalFrames.Count) * image.Size.Width * directionHorizontal, MidpointRounding.AwayFromZero);
var y = Math.Round((1f * i / finalFrames.Count) * image.Size.Height * directionVertical, MidpointRounding.AwayFromZero);
var leftPos = new Point(x - image.Size.Width, y - image.Size.Height);
var rightPos = new Point(x, y);
ctx.DrawImage(image, leftPos, 1f);
ctx.DrawImage(image, rightPos, 1f);
};
}
}