Currently, I am in the process of testing various methods for displaying images in a web browser. My goal is to develop a custom HTML element that can showcase a collection of images or frames as a continuous animation. The concept involves generating the images on the server side and streaming them to the client's browser. At the moment, the most straightforward approach appears to be utilizing the img
tag which consistently updates its src
attribute. To achieve this, I have subscribed to the onload
event, where upon loading an image, I update the image URL with a random timestamp. This action triggers a new request, creating an infinite loop that mimics an animated effect. While this solution is effective, it does impact CPU performance and lacks GPU acceleration.
Utilizing a Controller as the Image Source
[ApiController]
public class StreamController : ControllerBase
{
[Route("/source")]
public ActionResult Get()
{
var o = new Random();
var pos = o.Next(50, 150);
var map = new SKBitmap(250, 250);
var canvas = new SKCanvas(map);
var paint = new SKPaint
{
Color = SKColors.Black,
Style = SKPaintStyle.Fill,
FilterQuality = SKFilterQuality.High
};
canvas.DrawCircle(pos, pos, 20, paint);
var image = SKImage.FromBitmap(map);
var ms = new MemoryStream();
image.Encode(SKEncodedImageFormat.Png, 100).SaveTo(ms);
ms.Position = 0;
return new FileStreamResult(ms, "image/png");
}
}
HTML Implementation
@page "/"
<!-- Solution #1 : SRC attribute -->
<img
width="250"
height="250"
@onload="OnLoad"
src="@Source" />
<!-- Solution #2 : background style URL -->
<div
style="width: 250px; height: 250px; background: url(@Source)">
</div>
<!-- Solution #3 : SRC of the picture element - does not work -->
<picture style="width: 250px; height: 250px">
<source srcset="@Source" type="image/png" media="(min-width:250px)">
</picture>
@code
{
private Random _generator = new();
public string Source { get; set; } = "/source";
public void OnLoad()
{
// Creating an infinite loop of HTTP calls to animate by updating image source after loading the previous one
var uid = Guid.NewGuid().ToString("N");
var num = _generator.Next();
var stamp = DateTime.Now.Ticks;
Source = $"/source?{ uid }-{ num }-{ stamp }";
}
}
The Result
The red border signifies HTML animation, while the blue border represents CSS background. Note that the Picture tag did not render as expected.
Inquiries
- Why isn't solution #3, utilizing the
picture
element, functioning correctly? - What causes solution #2, using CSS background, to perform slower than solution #1 with the image tag? Why does it skip some frames and lack GPU acceleration?
- Is there a method to reduce CPU load by modifying something within the HTML or controller, such as transitioning to async streams in the controller or converting images into a video stream?
Update
A major issue has surfaced with refreshing the img
URL. It seems that the FileStreamResult
returned from the ASP controller becomes locked by an image, resulting in each image update request (e.g., /source?1, /source/2, /source?3) being cached by the browser. As a consequence, .NET struggles to release this resource, leading to a significant increase in memory usage.